From 9944e86ee3f69c75edd5a72ced30207a34538449 Mon Sep 17 00:00:00 2001
From: HueByte
Date: Thu, 16 Jul 2026 03:54:30 +0000
Subject: [PATCH] deploy: ce41ef9c0ae18d8f118d5caa68f8a4c29b7a7700
---
...choHub.Client.Commands.CommandHandler.html | 124 +-
.../EchoHub.Client.Config.ClientConfig.html | 66 +
.../EchoHub.Client.Config.SavedServer.html | 34 +
.../EchoHub.Client.Services.ApiClient.html | 175 +-
...ices.ChannelPasswordRequiredException.html | 275 ++
...choHub.Client.Services.ClipboardFiles.html | 219 ++
...Hub.Client.Services.EchoHubConnection.html | 52 +-
...oHub.Client.Services.FolderPickResult.html | 524 +++
.../EchoHub.Client.Services.JoinOutcome.html | 563 +++
...ub.Client.Services.NativeFolderPicker.html | 219 ++
...ub.Client.Services.OutgoingAttachment.html | 602 +++
...EchoHub.Client.Services.PickerOutcome.html | 159 +
.../EchoHub.Client.Services.RoomKeyStore.html | 407 ++
api/client/EchoHub.Client.Services.html | 52 +
.../EchoHub.Client.UI.Chat.ChatLine.html | 62 +-
...ient.UI.Dialogs.ChannelPasswordDialog.html | 249 ++
...Client.UI.Dialogs.CreateChannelResult.html | 47 +-
api/client/EchoHub.Client.UI.Dialogs.html | 6 +
...b.Client.UI.Helpers.DroppedFileParser.html | 266 ++
api/client/EchoHub.Client.UI.Helpers.html | 7 +
...ient.UI.ListSources.ChannelListSource.html | 8 +-
api/client/EchoHub.Client.UI.MainWindow.html | 105 +-
.../EchoHub.Core.Constants.HubConstants.html | 30 +
...ub.Core.Constants.ValidationConstants.html | 30 +
...choHub.Core.Contracts.ChannelListItem.html | 82 +-
...choHub.Core.Contracts.IChannelService.html | 180 +-
.../EchoHub.Core.Contracts.IChatService.html | 10 +-
api/core/EchoHub.Core.DTOs.AttachmentDto.html | 736 ++++
.../EchoHub.Core.DTOs.ChannelCryptoDto.html | 629 ++++
api/core/EchoHub.Core.DTOs.ChannelDto.html | 82 +-
...choHub.Core.DTOs.CreateChannelRequest.html | 127 +-
.../EchoHub.Core.DTOs.JoinChannelResult.html | 127 +-
api/core/EchoHub.Core.DTOs.MessageDto.html | 131 +-
...EchoHub.Core.DTOs.RekeyChannelRequest.html | 699 ++++
api/core/EchoHub.Core.DTOs.html | 19 +
api/core/EchoHub.Core.Models.Attachment.html | 465 +++
.../EchoHub.Core.Models.AttachmentKind.html | 158 +
api/core/EchoHub.Core.Models.Channel.html | 93 +
api/core/EchoHub.Core.Models.Message.html | 35 +-
api/core/EchoHub.Core.Models.html | 12 +
....Core.Security.RoomCrypto.DerivedKeys.html | 524 +++
.../EchoHub.Core.Security.RoomCrypto.html | 601 +++
api/core/EchoHub.Core.Security.html | 141 +
...b.Core.Services.FileValidationHelper.html} | 26 +-
...ub.Core.Services.ImageToAsciiService.html} | 32 +-
api/core/EchoHub.Core.Services.html | 130 +
.../EchoHub.Server.Irc.IrcNumericReply.html | 120 +
...Server.Controllers.ChannelsController.html | 175 +-
...rver.Controllers.ModerationController.html | 8 +-
...ub.Server.Controllers.UsersController.html | 4 +-
.../EchoHub.Server.Data.EchoHubDbContext.html | 31 +
...grations.AddChannelEncryptionEnvelope.html | 306 ++
...ata.Migrations.AddChannelPasswordHash.html | 306 ++
...Data.Migrations.AddMessageAttachments.html | 306 ++
.../EchoHub.Server.Data.Migrations.html | 12 +
api/server/EchoHub.Server.Hubs.ChatHub.html | 16 +-
...choHub.Server.Services.ChannelService.html | 187 +-
.../EchoHub.Server.Services.ChatService.html | 18 +-
...ub.Server.Services.FileStorageService.html | 35 +-
api/server/EchoHub.Server.Services.html | 8 -
api/toc.html | 86 +-
api/toc.json | 2 +-
articles/architecture.html | 2 +-
changelog/index.html | 1 +
changelog/toc.html | 3 +
changelog/toc.json | 2 +-
changelog/v0.2.12.html | 169 +
index.json | 211 +-
manifest.json | 374 +-
todo.html | 2 +-
xrefmap.yml | 3341 ++++++++++++++---
71 files changed, 14161 insertions(+), 884 deletions(-)
create mode 100644 api/client/EchoHub.Client.Services.ChannelPasswordRequiredException.html
create mode 100644 api/client/EchoHub.Client.Services.ClipboardFiles.html
create mode 100644 api/client/EchoHub.Client.Services.FolderPickResult.html
create mode 100644 api/client/EchoHub.Client.Services.JoinOutcome.html
create mode 100644 api/client/EchoHub.Client.Services.NativeFolderPicker.html
create mode 100644 api/client/EchoHub.Client.Services.OutgoingAttachment.html
create mode 100644 api/client/EchoHub.Client.Services.PickerOutcome.html
create mode 100644 api/client/EchoHub.Client.Services.RoomKeyStore.html
create mode 100644 api/client/EchoHub.Client.UI.Dialogs.ChannelPasswordDialog.html
create mode 100644 api/client/EchoHub.Client.UI.Helpers.DroppedFileParser.html
create mode 100644 api/core/EchoHub.Core.DTOs.AttachmentDto.html
create mode 100644 api/core/EchoHub.Core.DTOs.ChannelCryptoDto.html
create mode 100644 api/core/EchoHub.Core.DTOs.RekeyChannelRequest.html
create mode 100644 api/core/EchoHub.Core.Models.Attachment.html
create mode 100644 api/core/EchoHub.Core.Models.AttachmentKind.html
create mode 100644 api/core/EchoHub.Core.Security.RoomCrypto.DerivedKeys.html
create mode 100644 api/core/EchoHub.Core.Security.RoomCrypto.html
create mode 100644 api/core/EchoHub.Core.Security.html
rename api/{server/EchoHub.Server.Services.FileValidationHelper.html => core/EchoHub.Core.Services.FileValidationHelper.html} (81%)
rename api/{server/EchoHub.Server.Services.ImageToAsciiService.html => core/EchoHub.Core.Services.ImageToAsciiService.html} (80%)
create mode 100644 api/core/EchoHub.Core.Services.html
create mode 100644 api/server/EchoHub.Server.Data.Migrations.AddChannelEncryptionEnvelope.html
create mode 100644 api/server/EchoHub.Server.Data.Migrations.AddChannelPasswordHash.html
create mode 100644 api/server/EchoHub.Server.Data.Migrations.AddMessageAttachments.html
create mode 100644 changelog/v0.2.12.html
diff --git a/api/client/EchoHub.Client.Commands.CommandHandler.html b/api/client/EchoHub.Client.Commands.CommandHandler.html
index 6f8148a..7acdbbb 100644
--- a/api/client/EchoHub.Client.Commands.CommandHandler.html
+++ b/api/client/EchoHub.Client.Commands.CommandHandler.html
@@ -319,6 +319,66 @@ Class CommandHandler
+
+
+
+
+
+
+
public event Func<string, string, Task>? OnChangeRoomPassword
+
+
+
+
+
+
+
+ Event Type
+
+ Func <string , string , Task >
+
+
+
+
+
+
+
+
+
+
+
+ OnClearAttachments
+
+
+
+
+
+
+
+
public event Func<Task>? OnClearAttachments
+
+
+
+
+
+
+
+ Event Type
+
+ Func <Task >
+
+
+
+
+
+
+
+
+
+
OnHelp
@@ -358,7 +418,7 @@ Class CommandHandler
+
+
+
+
+
+
+
public event Func<string, Task>? OnSetAsciiSize
+
+
+
+
+
+
+
+ Event Type
+
+ Func <string , Task >
+
+
+
+
+
+
+
+
+
+
OnSetAvatar
@@ -709,6 +799,36 @@ Class CommandHandler
+
+
+
+
+
+
+
public event Func<string, Task>? OnSetDownloadPath
+
+
+
+
+
+
+
+ Event Type
+
+ Func <string , Task >
+
+
+
+
+
+
+
+
+
+
OnSetNick
diff --git a/api/client/EchoHub.Client.Config.ClientConfig.html b/api/client/EchoHub.Client.Config.ClientConfig.html
index 542225c..e934077 100644
--- a/api/client/EchoHub.Client.Config.ClientConfig.html
+++ b/api/client/EchoHub.Client.Config.ClientConfig.html
@@ -213,6 +213,39 @@ Class ClientConfig
+
+
+ DefaultAsciiSize
+
+
+
+ ASCII-art rendering size for images you attach: "s" (40×40), "m" (80×80), or "l" (120×120).
+Applies to copy-paste/drag-drop attachments, which have no per-file size flag.
+
+
+
+
+
public string DefaultAsciiSize { get; set; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
@@ -244,6 +277,39 @@ Class ClientConfig
+
+
+ DownloadPath
+
+
+
+ Folder where downloaded attachments and saved images are written. When null, the
+OS Downloads folder is used. Set via the native folder picker or /downloadpath.
+
+
+
+
+
public string? DownloadPath { get; set; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
diff --git a/api/client/EchoHub.Client.Config.SavedServer.html b/api/client/EchoHub.Client.Config.SavedServer.html
index 2b017ea..c9c5d00 100644
--- a/api/client/EchoHub.Client.Config.SavedServer.html
+++ b/api/client/EchoHub.Client.Config.SavedServer.html
@@ -182,6 +182,40 @@ Class SavedServer
+
+
+ ChannelKeys
+
+
+
+ Cached room content keys for end-to-end encrypted channels on this server,
+keyed by channel name (base64). Like RefreshToken, these live only on the
+user's machine — the server never sees them.
+
+
+
+
+
public Dictionary<string, string> ChannelKeys { get; set; }
+
+
+
+
+
+
+ Property Value
+
+ Dictionary <string , string >
+
+
+
+
+
+
+
+
+
+
diff --git a/api/client/EchoHub.Client.Services.ApiClient.html b/api/client/EchoHub.Client.Services.ApiClient.html
index 6b85df8..eb82300 100644
--- a/api/client/EchoHub.Client.Services.ApiClient.html
+++ b/api/client/EchoHub.Client.Services.ApiClient.html
@@ -365,8 +365,8 @@ Class ApiClient
-
- CreateChannelAsync(string, string?, bool)
+
+ CreateChannelAsync(string, string?, bool, string?, string?, string?)
@@ -374,7 +374,7 @@ Class ApiClient
+
+
+ GetChannelCryptoAsync(string)
+
+
+
+ Fetches a channel's public crypto metadata (whether it's E2E-encrypted and its
+key-derivation salt). Returns null when the channel doesn't exist.
+
+
+
+
+
public Task<ChannelCryptoDto?> GetChannelCryptoAsync(string channelName)
+
+
+ Parameters
+
+ channelName string
+
+
+
+ Returns
+
+ Task <ChannelCryptoDto >
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -991,6 +1035,89 @@ Used by EchoHubConnection for SignalR token provider.
+
+
+
+ RekeyChannelAsync(string, RekeyChannelRequest)
+
+
+
+
+
+
+
+
public Task<ChannelDto?> RekeyChannelAsync(string channelName, RekeyChannelRequest request)
+
+
+ Parameters
+
+ channelName string
+
+ request RekeyChannelRequest
+
+
+
+ Returns
+
+ Task <ChannelDto >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SendMessageWithAttachmentsAsync(string, string, IReadOnlyList<OutgoingAttachment>, string?)
+
+
+
+ Sends one message with optional text and one or more file attachments.
+For end-to-end encrypted channels each attachment carries a declared kind and a
+room-encrypted preview (empty when none); the caption is likewise room-encrypted.
+
+
+
+
+
public Task<MessageDto?> SendMessageWithAttachmentsAsync(string channelName, string content, IReadOnlyList<OutgoingAttachment> attachments, string? size = null)
+
+
+ Parameters
+
+ channelName string
+
+ content string
+
+ attachments IReadOnlyList <OutgoingAttachment >
+
+ size string
+
+
+
+ Returns
+
+ Task <MessageDto >
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1215,48 +1342,6 @@ Used by EchoHubConnection for SignalR token provider.
-
-
-
- UploadFileAsync(string, Stream, string, string?)
-
-
-
-
-
-
-
-
public Task<MessageDto?> UploadFileAsync(string channelName, Stream fileStream, string fileName, string? size = null)
-
-
- Parameters
-
- channelName string
-
- fileStream Stream
-
- fileName string
-
- size string
-
-
-
- Returns
-
- Task <MessageDto >
-
-
-
-
-
-
-
-
-
-
-
-
-
Events
diff --git a/api/client/EchoHub.Client.Services.ChannelPasswordRequiredException.html b/api/client/EchoHub.Client.Services.ChannelPasswordRequiredException.html
new file mode 100644
index 0000000..d4320df
--- /dev/null
+++ b/api/client/EchoHub.Client.Services.ChannelPasswordRequiredException.html
@@ -0,0 +1,275 @@
+
+
+
+
+ Class ChannelPasswordRequiredException | EchoHub Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Class ChannelPasswordRequiredException
+
+
+
+
Namespace EchoHub .Client .Services
+
Assembly EchoHub.Client.dll
+
+
+ Thrown when joining a channel fails because a password is required or incorrect.
+The UI catches this to prompt the user and retry.
+
+
+
+
+
public sealed class ChannelPasswordRequiredException : Exception
+
+
+
+
+
+
+ Inheritance
+
+
+
+ ChannelPasswordRequiredException
+
+
+
+
+
+
+ Inherited Members
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Constructors
+
+
+
+
+
+
+ ChannelPasswordRequiredException(string, string)
+
+
+
+
+
+
+
+
public ChannelPasswordRequiredException(string channelName, string message)
+
+
+ Parameters
+
+ channelName string
+
+ message string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties
+
+
+
+
+
+
+ ChannelName
+
+
+
+
+
+
+
+
public string ChannelName { get; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/client/EchoHub.Client.Services.ClipboardFiles.html b/api/client/EchoHub.Client.Services.ClipboardFiles.html
new file mode 100644
index 0000000..df0be62
--- /dev/null
+++ b/api/client/EchoHub.Client.Services.ClipboardFiles.html
@@ -0,0 +1,219 @@
+
+
+
+
+ Class ClipboardFiles | EchoHub Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Class ClipboardFiles
+
+
+
+
Namespace EchoHub .Client .Services
+
Assembly EchoHub.Client.dll
+
+
+ Reads file paths that live on the OS clipboard as a file list (e.g. after copying a file in
+Explorer/Finder/Nautilus), which terminals do not paste as text. Lets Ctrl+V attach a copied
+file directly instead of requiring the user to paste a raw path.
+
+
+
+
+
public static class ClipboardFiles
+
+
+
+
+
+
+ Inheritance
+
+
+ ClipboardFiles
+
+
+
+
+
+
+ Inherited Members
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+ TryGetFiles(out List<string>)
+
+
+
+
+
+
+
+
public static bool TryGetFiles(out List<string> files)
+
+
+ Parameters
+
+ files List <string >
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/client/EchoHub.Client.Services.EchoHubConnection.html b/api/client/EchoHub.Client.Services.EchoHubConnection.html
index 3e1c01c..b25f25f 100644
--- a/api/client/EchoHub.Client.Services.EchoHubConnection.html
+++ b/api/client/EchoHub.Client.Services.EchoHubConnection.html
@@ -157,8 +157,8 @@ Class EchoHubConnection
-
- EchoHubConnection(string, ApiClient, ClientEncryptionService)
+
+ EchoHubConnection(string, ApiClient, ClientEncryptionService, RoomKeyStore)
@@ -166,7 +166,7 @@ Class EchoHubConnection
+ roomKeys RoomKeyStore
+
@@ -190,6 +192,40 @@ Class EchoHubConnection
-
- JoinChannelAsync(string)
+
+ JoinChannelAsync(string, string?)
@@ -409,18 +445,20 @@ Class EchoHubConnection
+
+
+ AttachmentKind
+
+
+
+
+
+
+
+
public AttachmentKind? AttachmentKind { get; set; }
+
+
+
+
+
+
+ Property Value
+
+ AttachmentKind ?
+
+
+
+
+
+
+
+
+
+
@@ -465,37 +496,6 @@ Class ChatLine
-
-
- Type
-
-
-
-
-
-
-
-
public MessageType? Type { get; set; }
-
-
-
-
-
-
- Property Value
-
- MessageType ?
-
-
-
-
-
-
-
-
-
-
Methods
diff --git a/api/client/EchoHub.Client.UI.Dialogs.ChannelPasswordDialog.html b/api/client/EchoHub.Client.UI.Dialogs.ChannelPasswordDialog.html
new file mode 100644
index 0000000..3517f11
--- /dev/null
+++ b/api/client/EchoHub.Client.UI.Dialogs.ChannelPasswordDialog.html
@@ -0,0 +1,249 @@
+
+
+
+
+ Class ChannelPasswordDialog | EchoHub Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Class ChannelPasswordDialog
+
+
+
+
Namespace EchoHub .Client .UI .Dialogs
+
Assembly EchoHub.Client.dll
+
+
+ Prompts for a channel password when joining a protected channel.
+Returns the entered password, or null if the user cancels.
+
+
+
+
+
public sealed class ChannelPasswordDialog
+
+
+
+
+
+
+ Inheritance
+
+
+ ChannelPasswordDialog
+
+
+
+
+
+
+ Inherited Members
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Constructors
+
+
+
+
+
+
+ ChannelPasswordDialog()
+
+
+
+
+
+
+
+
public ChannelPasswordDialog()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+ Show(IApplication, string, string?)
+
+
+
+
+
+
+
+
public static string? Show(IApplication app, string channelName, string? message = null)
+
+
+ Parameters
+
+ app IApplication
+
+ channelName string
+
+ message string
+
+
+
+ Returns
+
+ string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html b/api/client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html
index 33fa451..bc8cb32 100644
--- a/api/client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html
+++ b/api/client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html
@@ -182,8 +182,8 @@ Class CreateChannelResult
-
- CreateChannelResult(string, string?, bool)
+
+ CreateChannelResult(string, string?, bool, string?)
@@ -191,7 +191,7 @@ Class CreateChannelResult
+ Password string
+
@@ -312,6 +314,37 @@ Class CreateChannelResult
+
+
+ Password
+
+
+
+
+
+
+
+
public string? Password { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
@@ -349,8 +382,8 @@ Class CreateChannelResult
-
- Deconstruct(out string, out string?, out bool)
+
+ Deconstruct(out string, out string?, out bool, out string?)
@@ -358,7 +391,7 @@ Class CreateChannelResult
+ Password string
+
diff --git a/api/client/EchoHub.Client.UI.Dialogs.html b/api/client/EchoHub.Client.UI.Dialogs.html
index f6cdf6f..c8098fa 100644
--- a/api/client/EchoHub.Client.UI.Dialogs.html
+++ b/api/client/EchoHub.Client.UI.Dialogs.html
@@ -98,6 +98,12 @@ Classes
AudioPlayerDialog
+
+ ChannelPasswordDialog
+ Prompts for a channel password when joining a protected channel.
+Returns the entered password, or null if the user cancels.
+
+
ConnectDialog
A Terminal.Gui dialog for entering server connection and authentication details.
diff --git a/api/client/EchoHub.Client.UI.Helpers.DroppedFileParser.html b/api/client/EchoHub.Client.UI.Helpers.DroppedFileParser.html
new file mode 100644
index 0000000..7d8b588
--- /dev/null
+++ b/api/client/EchoHub.Client.UI.Helpers.DroppedFileParser.html
@@ -0,0 +1,266 @@
+
+
+
+
+ Class DroppedFileParser | EchoHub Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Class DroppedFileParser
+
+
+
+
Namespace EchoHub .Client .UI .Helpers
+
Assembly EchoHub.Client.dll
+
+
+ Recognizes a dragged-and-dropped file (or files) that a terminal delivers into the input as an
+absolute path. Terminals differ: some paste the whole path at once, others send it character by
+character; either way this checks whether the current input text resolves to existing file(s).
+
+
+
+
+
public static class DroppedFileParser
+
+
+
+
+
+
+ Inheritance
+
+
+ DroppedFileParser
+
+
+
+
+
+
+ Inherited Members
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+ LooksLikePath(string)
+
+
+
+ Cheap pre-check so callers only stat the filesystem when the input plausibly holds a path:
+a quoted path, a Windows drive path (X:</code>/X:/), a UNC path (\), or a
+POSIX absolute path (/). Normal chat text never starts this way.
+
+
+
+
+
public static bool LooksLikePath(string text)
+
+
+ Parameters
+
+ text string
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TryGetFiles(string, out List<string>, Func<string, bool>?)
+
+
+
+ Returns true when text resolves to one or more existing files.
+Handles a single path (quoted or not, possibly containing spaces) and multiple
+space-separated (optionally quoted) paths. fileExists is injectable
+for testing; production passes Exists(string) .
+
+
+
+
+
public static bool TryGetFiles(string text, out List<string> files, Func<string, bool>? fileExists = null)
+
+
+ Parameters
+
+ text string
+
+ files List <string >
+
+ fileExists Func <string , bool >
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/client/EchoHub.Client.UI.Helpers.html b/api/client/EchoHub.Client.UI.Helpers.html
index d247dc5..c9f23d0 100644
--- a/api/client/EchoHub.Client.UI.Helpers.html
+++ b/api/client/EchoHub.Client.UI.Helpers.html
@@ -94,6 +94,13 @@
Classes
+
+ DroppedFileParser
+ Recognizes a dragged-and-dropped file (or files) that a terminal delivers into the input as an
+absolute path. Terminals differ: some paste the whole path at once, others send it character by
+character; either way this checks whether the current input text resolves to existing file(s).
+
+
EmojiHelper
Converts emoji grapheme clusters to text shortcodes for safe TUI rendering.
diff --git a/api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html b/api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html
index 83ce409..91e77d9 100644
--- a/api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html
+++ b/api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html
@@ -459,8 +459,8 @@ Active channel gets a > indicator, unread channels are bright with a count ba
-
- Update(List<string>, Dictionary<string, int>, string)
+
+ Update(List<string>, Dictionary<string, int>, string, IReadOnlySet<string>?)
@@ -468,7 +468,7 @@ Active channel gets a > indicator, unread channels are bright with a count ba
-
public void Update(List<string> channels, Dictionary<string, int> unread, string activeChannel)
+
public void Update(List<string> channels, Dictionary<string, int> unread, string activeChannel, IReadOnlySet<string>? protectedChannels = null)
Parameters
@@ -479,6 +479,8 @@ Active channel gets a > indicator, unread channels are bright with a count ba
activeChannel string
+ protectedChannels IReadOnlySet <string >
+
diff --git a/api/client/EchoHub.Client.UI.MainWindow.html b/api/client/EchoHub.Client.UI.MainWindow.html
index 461d0bb..1298eb9 100644
--- a/api/client/EchoHub.Client.UI.MainWindow.html
+++ b/api/client/EchoHub.Client.UI.MainWindow.html
@@ -943,8 +943,8 @@ Call after theme changes to refresh colors.
-
- EnsureChannelInList(string, bool?)
+
+ EnsureChannelInList(string, bool?, bool?)
@@ -953,7 +953,7 @@ Call after theme changes to refresh colors.
-
public void EnsureChannelInList(string channelName, bool? isPublic = null)
+
public void EnsureChannelInList(string channelName, bool? isPublic = null, bool? isProtected = null)
Parameters
@@ -962,6 +962,8 @@ Call after theme changes to refresh colors.
isPublic bool ?
+ isProtected bool ?
+
@@ -1191,6 +1193,41 @@ Call after theme changes to refresh colors.
+
+
+
+ SetStagedAttachments(IReadOnlyList<string>, string)
+
+
+
+ Updates the attachment staging indicator shown on the input frame's title, including the
+current ASCII-art size for images. Passing an empty list restores the default hint.
+
+
+
+
+
public void SetStagedAttachments(IReadOnlyList<string> fileNames, string asciiSizeLabel)
+
+
+ Parameters
+
+ fileNames IReadOnlyList <string >
+
+ asciiSizeLabel string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1568,6 +1605,37 @@ Call after theme changes to refresh colors.
+
+ OnDeleteMessageRequested
+
+
+
+ Fired when the user presses Delete on the selected message. Parameter is the message id.
+
+
+
+
+
public event Action<Guid>? OnDeleteMessageRequested
+
+
+
+
+
+
+
+ Event Type
+
+ Action <Guid >
+
+
+
+
+
+
+
+
+
+
OnDisconnectRequested
@@ -1630,6 +1698,37 @@ Call after theme changes to refresh colors.
+
+ OnImageSaveRequested
+
+
+
+ Fired when the user activates an image's "[save original]" line. Parameters: attachmentUrl, fileName.
+
+
+
+
+
public event Action<string, string>? OnImageSaveRequested
+
+
+
+
+
+
+
+ Event Type
+
+ Action <string , string >
+
+
+
+
+
+
+
+
+
+
OnLoadMoreRequested
diff --git a/api/core/EchoHub.Core.Constants.HubConstants.html b/api/core/EchoHub.Core.Constants.HubConstants.html
index 64fe4d3..393a537 100644
--- a/api/core/EchoHub.Core.Constants.HubConstants.html
+++ b/api/core/EchoHub.Core.Constants.HubConstants.html
@@ -453,6 +453,36 @@ Class HubConstants
+
+
+
+
+
+
+
public const int MaxAttachmentsPerMessage = 10
+
+
+
+
+
+ Field Value
+
+ int
+
+
+
+
+
+
+
+
+
+
+
+
MaxAudioFileSizeBytes
diff --git a/api/core/EchoHub.Core.Constants.ValidationConstants.html b/api/core/EchoHub.Core.Constants.ValidationConstants.html
index 2963158..664a0d4 100644
--- a/api/core/EchoHub.Core.Constants.ValidationConstants.html
+++ b/api/core/EchoHub.Core.Constants.ValidationConstants.html
@@ -393,6 +393,36 @@ Class ValidationConstants
+
+
+
+
+
+
+
public const int MinChannelPasswordLength = 3
+
+
+
+
+
+ Field Value
+
+ int
+
+
+
+
+
+
+
+
+
+
+
+
UsernamePattern
diff --git a/api/core/EchoHub.Core.Contracts.ChannelListItem.html b/api/core/EchoHub.Core.Contracts.ChannelListItem.html
index 85ae4b9..7186359 100644
--- a/api/core/EchoHub.Core.Contracts.ChannelListItem.html
+++ b/api/core/EchoHub.Core.Contracts.ChannelListItem.html
@@ -182,8 +182,8 @@ Class ChannelListItem
-
- ChannelListItem(string, string?, int)
+
+ ChannelListItem(string, string?, int, bool, bool)
@@ -191,7 +191,7 @@ Class ChannelListItem
+ IsPublic bool
+
+ IsProtected bool
+
@@ -250,6 +254,68 @@ Class ChannelListItem
+
+
+ IsProtected
+
+
+
+
+
+
+
+
public bool IsProtected { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IsPublic
+
+
+
+
+
+
+
+
public bool IsPublic { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ bool
+
+
+
+
+
+
+
+
+
+
@@ -349,8 +415,8 @@ Class ChannelListItem
-
- Deconstruct(out string, out string?, out int)
+
+ Deconstruct(out string, out string?, out int, out bool, out bool)
@@ -358,7 +424,7 @@ Class ChannelListItem
+ IsPublic bool
+
+ IsProtected bool
+
diff --git a/api/core/EchoHub.Core.Contracts.IChannelService.html b/api/core/EchoHub.Core.Contracts.IChannelService.html
index e289cc7..9eb6fe7 100644
--- a/api/core/EchoHub.Core.Contracts.IChannelService.html
+++ b/api/core/EchoHub.Core.Contracts.IChannelService.html
@@ -122,8 +122,8 @@ Interface IChannelService
-
- CreateChannelAsync(Guid, string, string?, bool)
+
+ CreateChannelAsync(Guid, string, string?, bool, string?, string?, string?)
@@ -131,7 +131,7 @@ Interface IChannelService
+ password string
+
+ encryptionSalt string
+
+ wrappedRoomKey string
+
Returns
@@ -202,8 +208,8 @@ Interface IChannelService
-
- EnsureChannelMembershipAsync(Guid, string)
+
+ EnsureChannelMembershipAsync(Guid, string, string?)
@@ -211,7 +217,7 @@ Interface IChannelService
+ password string
+
Returns
- Task <(bool Success , string Error )>
+ Task <(bool Success , string Error , bool PasswordRequired )>
@@ -274,6 +282,78 @@ Interface IChannelService
+
+
+ GetChannelCryptoAsync(string)
+
+
+
+
+
+
+
+
Task<ChannelCryptoDto?> GetChannelCryptoAsync(string channelName)
+
+
+ Parameters
+
+ channelName string
+
+
+
+ Returns
+
+ Task <ChannelCryptoDto >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GetChannelKeyEnvelopeAsync(string)
+
+
+
+
+
+
+
+
Task<(string? EncryptionSalt, string? WrappedRoomKey)> GetChannelKeyEnvelopeAsync(string channelName)
+
+
+ Parameters
+
+ channelName string
+
+
+
+ Returns
+
+ Task <(string EncryptionSalt , string WrappedRoomKey )>
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -381,6 +461,92 @@ Interface IChannelService
+
+
+ RekeyChannelAsync(Guid, string, string, string, string, string)
+
+
+
+
+
+
+
+
Task<ChannelOperationResult> RekeyChannelAsync(Guid callerUserId, string channelName, string oldPassword, string newPassword, string newEncryptionSalt, string newWrappedRoomKey)
+
+
+ Parameters
+
+ callerUserId Guid
+
+ channelName string
+
+ oldPassword string
+
+ newPassword string
+
+ newEncryptionSalt string
+
+ newWrappedRoomKey string
+
+
+
+ Returns
+
+ Task <ChannelOperationResult >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetChannelPasswordAsync(Guid, string, string?)
+
+
+
+
+
+
+
+
Task<ChannelOperationResult> SetChannelPasswordAsync(Guid callerUserId, string channelName, string? password)
+
+
+ Parameters
+
+ callerUserId Guid
+
+ channelName string
+
+ password string
+
+
+
+ Returns
+
+ Task <ChannelOperationResult >
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/core/EchoHub.Core.Contracts.IChatService.html b/api/core/EchoHub.Core.Contracts.IChatService.html
index 0803da2..3798d96 100644
--- a/api/core/EchoHub.Core.Contracts.IChatService.html
+++ b/api/core/EchoHub.Core.Contracts.IChatService.html
@@ -310,8 +310,8 @@ Interface IChatService
-
- JoinChannelAsync(string, Guid, string, string)
+
+ JoinChannelAsync(string, Guid, string, string, string?)
@@ -319,7 +319,7 @@ Interface IChatService
+ password string
+
Returns
- Task <(List <MessageDto > History , string Error )>
+ Task <(List <MessageDto > History , string Error , bool PasswordRequired )>
diff --git a/api/core/EchoHub.Core.DTOs.AttachmentDto.html b/api/core/EchoHub.Core.DTOs.AttachmentDto.html
new file mode 100644
index 0000000..74a2ec6
--- /dev/null
+++ b/api/core/EchoHub.Core.DTOs.AttachmentDto.html
@@ -0,0 +1,736 @@
+
+
+
+
+ Class AttachmentDto | EchoHub Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Class AttachmentDto
+
+
+
+
Namespace EchoHub .Core .DTOs
+
Assembly EchoHub.Core.dll
+
+
+ A file attached to a message. AsciiPreview holds the color-tag art for
+images (null otherwise). For end-to-end encrypted channels the content behind
+Url and the preview are ciphertext the server cannot read.
+
+
+
+
+
public record AttachmentDto : IEquatable<AttachmentDto>
+
+
+
+
+
+
+ Inheritance
+
+
+ AttachmentDto
+
+
+
+
+ Implements
+
+
+
+
+
+
+
+ Inherited Members
+
+
+
+
+
+
+
+
+
+
+
+
+ Constructors
+
+
+
+
+
+
+ AttachmentDto(AttachmentDto)
+
+
+
+
+
+
+
+
protected AttachmentDto(AttachmentDto original)
+
+
+ Parameters
+
+ original AttachmentDto
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AttachmentDto(AttachmentKind, string, string, long, string?)
+
+
+
+ A file attached to a message. AsciiPreview holds the color-tag art for
+images (null otherwise). For end-to-end encrypted channels the content behind
+Url and the preview are ciphertext the server cannot read.
+
+
+
+
+
public AttachmentDto(AttachmentKind Kind, string Url, string FileName, long FileSize, string? AsciiPreview = null)
+
+
+ Parameters
+
+ Kind AttachmentKind
+
+ Url string
+
+ FileName string
+
+ FileSize long
+
+ AsciiPreview string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties
+
+
+
+
+
+
+ AsciiPreview
+
+
+
+
+
+
+
+
public string? AsciiPreview { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
+
+
+
+ EqualityContract
+
+
+
+
+
+
+
+
protected virtual Type EqualityContract { get; }
+
+
+
+
+
+
+ Property Value
+
+ Type
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FileName
+
+
+
+
+
+
+
+
public string FileName { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FileSize
+
+
+
+
+
+
+
+
public long FileSize { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ long
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Kind
+
+
+
+
+
+
+
+
public AttachmentKind Kind { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ AttachmentKind
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Url
+
+
+
+
+
+
+
+
public string Url { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+ Deconstruct(out AttachmentKind, out string, out string, out long, out string?)
+
+
+
+
+
+
+
+
public void Deconstruct(out AttachmentKind Kind, out string Url, out string FileName, out long FileSize, out string? AsciiPreview)
+
+
+ Parameters
+
+ Kind AttachmentKind
+
+ Url string
+
+ FileName string
+
+ FileSize long
+
+ AsciiPreview string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Equals(AttachmentDto?)
+
+
+
+
+
+
+
+
public virtual bool Equals(AttachmentDto? other)
+
+
+ Parameters
+
+ other AttachmentDto
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Equals(object?)
+
+
+
+
+
+
+
+
public override bool Equals(object? obj)
+
+
+ Parameters
+
+ obj object
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GetHashCode()
+
+
+
+
+
+
+
+
public override int GetHashCode()
+
+
+
+ Returns
+
+ int
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PrintMembers(StringBuilder)
+
+
+
+
+
+
+
+
protected virtual bool PrintMembers(StringBuilder builder)
+
+
+ Parameters
+
+ builder StringBuilder
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ToString()
+
+
+
+
+
+
+
+
public override string ToString()
+
+
+
+ Returns
+
+ string
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Operators
+
+
+
+
+
+
+ operator ==(AttachmentDto?, AttachmentDto?)
+
+
+
+
+
+
+
+
public static bool operator ==(AttachmentDto? left, AttachmentDto? right)
+
+
+ Parameters
+
+ left AttachmentDto
+
+ right AttachmentDto
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ operator !=(AttachmentDto?, AttachmentDto?)
+
+
+
+
+
+
+
+
public static bool operator !=(AttachmentDto? left, AttachmentDto? right)
+
+
+ Parameters
+
+ left AttachmentDto
+
+ right AttachmentDto
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/core/EchoHub.Core.DTOs.ChannelCryptoDto.html b/api/core/EchoHub.Core.DTOs.ChannelCryptoDto.html
new file mode 100644
index 0000000..d956d01
--- /dev/null
+++ b/api/core/EchoHub.Core.DTOs.ChannelCryptoDto.html
@@ -0,0 +1,629 @@
+
+
+
+
+ Class ChannelCryptoDto | EchoHub Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Class ChannelCryptoDto
+
+
+
+
Namespace EchoHub .Core .DTOs
+
Assembly EchoHub.Core.dll
+
+
+ Public crypto metadata for a channel — enough for a client to derive its join
+credential from a passphrase. Never includes the wrapped room key.
+
+
+
+
+
public record ChannelCryptoDto : IEquatable<ChannelCryptoDto>
+
+
+
+
+
+
+ Inheritance
+
+
+ ChannelCryptoDto
+
+
+
+
+ Implements
+
+
+
+
+
+
+
+ Inherited Members
+
+
+
+
+
+
+
+
+
+
+
+
+ Constructors
+
+
+
+
+
+
+ ChannelCryptoDto(ChannelCryptoDto)
+
+
+
+
+
+
+
+
protected ChannelCryptoDto(ChannelCryptoDto original)
+
+
+ Parameters
+
+ original ChannelCryptoDto
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChannelCryptoDto(bool, string?)
+
+
+
+ Public crypto metadata for a channel — enough for a client to derive its join
+credential from a passphrase. Never includes the wrapped room key.
+
+
+
+
+
public ChannelCryptoDto(bool IsEncrypted, string? EncryptionSalt)
+
+
+ Parameters
+
+ IsEncrypted bool
+
+ EncryptionSalt string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties
+
+
+
+
+
+
+ EncryptionSalt
+
+
+
+
+
+
+
+
public string? EncryptionSalt { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
+
+
+
+ EqualityContract
+
+
+
+
+
+
+
+
protected virtual Type EqualityContract { get; }
+
+
+
+
+
+
+ Property Value
+
+ Type
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IsEncrypted
+
+
+
+
+
+
+
+
public bool IsEncrypted { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ bool
+
+
+
+
+
+
+
+
+
+
+ Methods
+
+
+
+
+
+
+ Deconstruct(out bool, out string?)
+
+
+
+
+
+
+
+
public void Deconstruct(out bool IsEncrypted, out string? EncryptionSalt)
+
+
+ Parameters
+
+ IsEncrypted bool
+
+ EncryptionSalt string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Equals(ChannelCryptoDto?)
+
+
+
+
+
+
+
+
public virtual bool Equals(ChannelCryptoDto? other)
+
+
+ Parameters
+
+ other ChannelCryptoDto
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Equals(object?)
+
+
+
+
+
+
+
+
public override bool Equals(object? obj)
+
+
+ Parameters
+
+ obj object
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GetHashCode()
+
+
+
+
+
+
+
+
public override int GetHashCode()
+
+
+
+ Returns
+
+ int
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PrintMembers(StringBuilder)
+
+
+
+
+
+
+
+
protected virtual bool PrintMembers(StringBuilder builder)
+
+
+ Parameters
+
+ builder StringBuilder
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ToString()
+
+
+
+
+
+
+
+
public override string ToString()
+
+
+
+ Returns
+
+ string
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Operators
+
+
+
+
+
+
+ operator ==(ChannelCryptoDto?, ChannelCryptoDto?)
+
+
+
+
+
+
+
+
public static bool operator ==(ChannelCryptoDto? left, ChannelCryptoDto? right)
+
+
+ Parameters
+
+ left ChannelCryptoDto
+
+ right ChannelCryptoDto
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ operator !=(ChannelCryptoDto?, ChannelCryptoDto?)
+
+
+
+
+
+
+
+
public static bool operator !=(ChannelCryptoDto? left, ChannelCryptoDto? right)
+
+
+ Parameters
+
+ left ChannelCryptoDto
+
+ right ChannelCryptoDto
+
+
+
+ Returns
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api/core/EchoHub.Core.DTOs.ChannelDto.html b/api/core/EchoHub.Core.DTOs.ChannelDto.html
index bfd86cd..dbcc195 100644
--- a/api/core/EchoHub.Core.DTOs.ChannelDto.html
+++ b/api/core/EchoHub.Core.DTOs.ChannelDto.html
@@ -182,8 +182,8 @@ Class ChannelDto
-
- ChannelDto(Guid, string, string?, bool, int, DateTimeOffset)
+
+ ChannelDto(Guid, string, string?, bool, int, DateTimeOffset, bool, bool)
@@ -191,7 +191,7 @@ Class ChannelDto
+
+
+ IsEncrypted
+
+
+
+
+
+
+
+
public bool IsEncrypted { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ bool
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IsProtected
+
+
+
+
+
+
+
+
public bool IsProtected { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ bool
+
+
+
+
+
+
+
+
+
+
@@ -448,8 +514,8 @@ Class ChannelDto
-
- Deconstruct(out Guid, out string, out string?, out bool, out int, out DateTimeOffset)
+
+ Deconstruct(out Guid, out string, out string?, out bool, out int, out DateTimeOffset, out bool, out bool)
@@ -457,7 +523,7 @@ Class ChannelDto
-
- CreateChannelRequest(string, string?, bool)
+
+ CreateChannelRequest(string, string?, bool, string?, string?, string?)
@@ -191,7 +191,7 @@ Class CreateChannelRequest
+ Password string
+
+ EncryptionSalt string
+
+ WrappedRoomKey string
+
@@ -219,6 +225,37 @@ Class CreateChannelRequest
+
+
+ EncryptionSalt
+
+
+
+
+
+
+
+
public string? EncryptionSalt { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
@@ -312,6 +349,37 @@ Class CreateChannelRequest
+
+
+ Password
+
+
+
+
+
+
+
+
public string? Password { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
@@ -343,14 +411,10 @@ Class CreateChannelRequest
-
-
-
-
- Deconstruct(out string, out string?, out bool)
+
+ WrappedRoomKey
@@ -358,7 +422,42 @@ Class CreateChannelRequest
+
+
+ Deconstruct(out string, out string?, out bool, out string?, out string?, out string?)
+
+
+
+
+
+
+
+
public void Deconstruct(out string Name, out string? Topic, out bool IsPublic, out string? Password, out string? EncryptionSalt, out string? WrappedRoomKey)
Parameters
@@ -369,6 +468,12 @@ Class CreateChannelRequest
+ Password string
+
+ EncryptionSalt string
+
+ WrappedRoomKey string
+
diff --git a/api/core/EchoHub.Core.DTOs.JoinChannelResult.html b/api/core/EchoHub.Core.DTOs.JoinChannelResult.html
index fab53e8..956a064 100644
--- a/api/core/EchoHub.Core.DTOs.JoinChannelResult.html
+++ b/api/core/EchoHub.Core.DTOs.JoinChannelResult.html
@@ -182,8 +182,8 @@ Class JoinChannelResult
-
- JoinChannelResult(bool, List<MessageDto>, string?)
+
+ JoinChannelResult(bool, List<MessageDto>, string?, bool, string?, string?)
@@ -191,7 +191,7 @@ Class JoinChannelResult
+ PasswordRequired bool
+
+ EncryptionSalt string
+
+ WrappedRoomKey string
+
@@ -219,6 +225,37 @@ Class JoinChannelResult
+
+
+ EncryptionSalt
+
+
+
+
+
+
+
+
public string? EncryptionSalt { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ string
+
+
+
+
+
+
+
+
+
+
@@ -312,6 +349,37 @@ Class JoinChannelResult
+
+
+ PasswordRequired
+
+
+
+
+
+
+
+
public bool PasswordRequired { get; init; }
+
+
+
+
+
+
+ Property Value
+
+ bool
+
+
+
+
+
+
+
+
+
+
@@ -343,14 +411,10 @@ Class JoinChannelResult
-
-
-
-
- Deconstruct(out bool, out List<MessageDto>, out string?)
+
+ WrappedRoomKey
@@ -358,7 +422,42 @@ Class JoinChannelResult
+
+
+ Deconstruct(out bool, out List<MessageDto>, out string?, out bool, out string?, out string?)
+
+
+
+
+
+
+
+
public void Deconstruct(out bool Success, out List<MessageDto> History, out string? Error, out bool PasswordRequired, out string? EncryptionSalt, out string? WrappedRoomKey)
Parameters
@@ -369,6 +468,12 @@ Class JoinChannelResult
+ PasswordRequired bool
+
+ EncryptionSalt string
+
+ WrappedRoomKey string
+
diff --git a/api/core/EchoHub.Core.DTOs.MessageDto.html b/api/core/EchoHub.Core.DTOs.MessageDto.html
index 11718ac..174ec9a 100644
--- a/api/core/EchoHub.Core.DTOs.MessageDto.html
+++ b/api/core/EchoHub.Core.DTOs.MessageDto.html
@@ -182,8 +182,8 @@ Class MessageDto
-
- MessageDto(Guid, string, string, string?, string, MessageType, string?, string?, DateTimeOffset, long?, List<EmbedDto>?)
+
+ MessageDto(Guid, string, string, string?, string, DateTimeOffset, List<AttachmentDto>?, List<EmbedDto>?)
@@ -191,7 +191,7 @@ Class MessageDto
+
-
- AttachmentFileName
+
+ Attachments
@@ -246,7 +240,7 @@ Class MessageDto
-
-
- AttachmentFileSize
-
-
-
-
-
-
-
-
public long? AttachmentFileSize { get; init; }
-
-
-
-
-
-
- Property Value
-
- long ?
-
-
-
-
-
-
-
-
-
-
-
-
-
- AttachmentUrl
-
-
-
-
-
-
-
-
public string? AttachmentUrl { get; init; }
-
-
-
-
-
-
- Property Value
-
- string
+ List <AttachmentDto >
@@ -576,45 +508,14 @@ Class MessageDto
-
-
- Type
-
-
-
-
-
-
-
-
public MessageType Type { get; init; }
-
-
-
-
-
-
- Property Value
-
- MessageType
-
-
-
-
-
-
-
-
-
-
Methods
-
- Deconstruct(out Guid, out string, out string, out string?, out string, out MessageType, out string?, out string?, out DateTimeOffset, out long?, out List<EmbedDto>?)
+
+ Deconstruct(out Guid, out string, out string, out string?, out string, out DateTimeOffset, out List<AttachmentDto>?, out List<EmbedDto>?)
@@ -622,7 +523,7 @@ Class MessageDto
-
@@ -512,15 +583,24 @@
AddAttachmentFileSize
+
+ AddChannelEncryptionEnvelope
+
AddChannelIsPublic
AddChannelMembership
+
+ AddChannelPasswordHash
+
AddEncryptionSupport
+
+ AddMessageAttachments
+
AddMessageEmbed
@@ -562,12 +642,6 @@
FileStorageService
-
- FileValidationHelper
-
-
- ImageToAsciiService
-
LinkEmbedService
diff --git a/api/toc.json b/api/toc.json
index d69df73..c755f2b 100644
--- a/api/toc.json
+++ b/api/toc.json
@@ -1,2 +1,2 @@
-{"items":[{"name":"Client","items":[{"name":"API Reference","includedFrom":"~/_api_meta/client/toc.yml","items":[{"name":"EchoHub.Client","href":"client/EchoHub.Client.html","topicHref":"client/EchoHub.Client.html","topicUid":"EchoHub.Client","type":"Namespace","items":[{"name":"AppOrchestrator","href":"client/EchoHub.Client.AppOrchestrator.html","topicHref":"client/EchoHub.Client.AppOrchestrator.html","topicUid":"EchoHub.Client.AppOrchestrator","type":"Class"}]},{"name":"EchoHub.Client.Commands","href":"client/EchoHub.Client.Commands.html","topicHref":"client/EchoHub.Client.Commands.html","topicUid":"EchoHub.Client.Commands","type":"Namespace","items":[{"name":"CommandHandler","href":"client/EchoHub.Client.Commands.CommandHandler.html","topicHref":"client/EchoHub.Client.Commands.CommandHandler.html","topicUid":"EchoHub.Client.Commands.CommandHandler","type":"Class"},{"name":"CommandResult","href":"client/EchoHub.Client.Commands.CommandResult.html","topicHref":"client/EchoHub.Client.Commands.CommandResult.html","topicUid":"EchoHub.Client.Commands.CommandResult","type":"Class"}]},{"name":"EchoHub.Client.Config","href":"client/EchoHub.Client.Config.html","topicHref":"client/EchoHub.Client.Config.html","topicUid":"EchoHub.Client.Config","type":"Namespace","items":[{"name":"AccountPreset","href":"client/EchoHub.Client.Config.AccountPreset.html","topicHref":"client/EchoHub.Client.Config.AccountPreset.html","topicUid":"EchoHub.Client.Config.AccountPreset","type":"Class"},{"name":"ClientConfig","href":"client/EchoHub.Client.Config.ClientConfig.html","topicHref":"client/EchoHub.Client.Config.ClientConfig.html","topicUid":"EchoHub.Client.Config.ClientConfig","type":"Class"},{"name":"ConfigManager","href":"client/EchoHub.Client.Config.ConfigManager.html","topicHref":"client/EchoHub.Client.Config.ConfigManager.html","topicUid":"EchoHub.Client.Config.ConfigManager","type":"Class"},{"name":"NotificationConfig","href":"client/EchoHub.Client.Config.NotificationConfig.html","topicHref":"client/EchoHub.Client.Config.NotificationConfig.html","topicUid":"EchoHub.Client.Config.NotificationConfig","type":"Class"},{"name":"SavedServer","href":"client/EchoHub.Client.Config.SavedServer.html","topicHref":"client/EchoHub.Client.Config.SavedServer.html","topicUid":"EchoHub.Client.Config.SavedServer","type":"Class"}]},{"name":"EchoHub.Client.Services","href":"client/EchoHub.Client.Services.html","topicHref":"client/EchoHub.Client.Services.html","topicUid":"EchoHub.Client.Services","type":"Namespace","items":[{"name":"ApiClient","href":"client/EchoHub.Client.Services.ApiClient.html","topicHref":"client/EchoHub.Client.Services.ApiClient.html","topicUid":"EchoHub.Client.Services.ApiClient","type":"Class"},{"name":"AsyncRunner","href":"client/EchoHub.Client.Services.AsyncRunner.html","topicHref":"client/EchoHub.Client.Services.AsyncRunner.html","topicUid":"EchoHub.Client.Services.AsyncRunner","type":"Class"},{"name":"AudioPlaybackService","href":"client/EchoHub.Client.Services.AudioPlaybackService.html","topicHref":"client/EchoHub.Client.Services.AudioPlaybackService.html","topicUid":"EchoHub.Client.Services.AudioPlaybackService","type":"Class"},{"name":"BackupInfo","href":"client/EchoHub.Client.Services.BackupInfo.html","topicHref":"client/EchoHub.Client.Services.BackupInfo.html","topicUid":"EchoHub.Client.Services.BackupInfo","type":"Class"},{"name":"ClientEncryptionService","href":"client/EchoHub.Client.Services.ClientEncryptionService.html","topicHref":"client/EchoHub.Client.Services.ClientEncryptionService.html","topicUid":"EchoHub.Client.Services.ClientEncryptionService","type":"Class"},{"name":"EchoHubConnection","href":"client/EchoHub.Client.Services.EchoHubConnection.html","topicHref":"client/EchoHub.Client.Services.EchoHubConnection.html","topicUid":"EchoHub.Client.Services.EchoHubConnection","type":"Class"},{"name":"NotificationSoundService","href":"client/EchoHub.Client.Services.NotificationSoundService.html","topicHref":"client/EchoHub.Client.Services.NotificationSoundService.html","topicUid":"EchoHub.Client.Services.NotificationSoundService","type":"Class"},{"name":"PathSetup","href":"client/EchoHub.Client.Services.PathSetup.html","topicHref":"client/EchoHub.Client.Services.PathSetup.html","topicUid":"EchoHub.Client.Services.PathSetup","type":"Class"},{"name":"UpdateBackupService","href":"client/EchoHub.Client.Services.UpdateBackupService.html","topicHref":"client/EchoHub.Client.Services.UpdateBackupService.html","topicUid":"EchoHub.Client.Services.UpdateBackupService","type":"Class"},{"name":"UpdateChecker","href":"client/EchoHub.Client.Services.UpdateChecker.html","topicHref":"client/EchoHub.Client.Services.UpdateChecker.html","topicUid":"EchoHub.Client.Services.UpdateChecker","type":"Class"}]},{"name":"EchoHub.Client.Themes","href":"client/EchoHub.Client.Themes.html","topicHref":"client/EchoHub.Client.Themes.html","topicUid":"EchoHub.Client.Themes","type":"Namespace","items":[{"name":"Theme","href":"client/EchoHub.Client.Themes.Theme.html","topicHref":"client/EchoHub.Client.Themes.Theme.html","topicUid":"EchoHub.Client.Themes.Theme","type":"Class"},{"name":"ThemeColors","href":"client/EchoHub.Client.Themes.ThemeColors.html","topicHref":"client/EchoHub.Client.Themes.ThemeColors.html","topicUid":"EchoHub.Client.Themes.ThemeColors","type":"Class"},{"name":"ThemeManager","href":"client/EchoHub.Client.Themes.ThemeManager.html","topicHref":"client/EchoHub.Client.Themes.ThemeManager.html","topicUid":"EchoHub.Client.Themes.ThemeManager","type":"Class"}]},{"name":"EchoHub.Client.UI","href":"client/EchoHub.Client.UI.html","topicHref":"client/EchoHub.Client.UI.html","topicUid":"EchoHub.Client.UI","type":"Namespace","items":[{"name":"MainWindow","href":"client/EchoHub.Client.UI.MainWindow.html","topicHref":"client/EchoHub.Client.UI.MainWindow.html","topicUid":"EchoHub.Client.UI.MainWindow","type":"Class"}]},{"name":"EchoHub.Client.UI.Chat","href":"client/EchoHub.Client.UI.Chat.html","topicHref":"client/EchoHub.Client.UI.Chat.html","topicUid":"EchoHub.Client.UI.Chat","type":"Namespace","items":[{"name":"ChatColors","href":"client/EchoHub.Client.UI.Chat.ChatColors.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatColors.html","topicUid":"EchoHub.Client.UI.Chat.ChatColors","type":"Class"},{"name":"ChatLine","href":"client/EchoHub.Client.UI.Chat.ChatLine.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatLine.html","topicUid":"EchoHub.Client.UI.Chat.ChatLine","type":"Class"},{"name":"ChatListSource","href":"client/EchoHub.Client.UI.Chat.ChatListSource.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatListSource.html","topicUid":"EchoHub.Client.UI.Chat.ChatListSource","type":"Class"},{"name":"ChatMessageManager","href":"client/EchoHub.Client.UI.Chat.ChatMessageManager.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatMessageManager.html","topicUid":"EchoHub.Client.UI.Chat.ChatMessageManager","type":"Class"},{"name":"ChatSegment","href":"client/EchoHub.Client.UI.Chat.ChatSegment.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatSegment.html","topicUid":"EchoHub.Client.UI.Chat.ChatSegment","type":"Class"}]},{"name":"EchoHub.Client.UI.Dialogs","href":"client/EchoHub.Client.UI.Dialogs.html","topicHref":"client/EchoHub.Client.UI.Dialogs.html","topicUid":"EchoHub.Client.UI.Dialogs","type":"Namespace","items":[{"name":"AudioPlayerDialog","href":"client/EchoHub.Client.UI.Dialogs.AudioPlayerDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.AudioPlayerDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.AudioPlayerDialog","type":"Class"},{"name":"ConnectDialog","href":"client/EchoHub.Client.UI.Dialogs.ConnectDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ConnectDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.ConnectDialog","type":"Class"},{"name":"ConnectDialogResult","href":"client/EchoHub.Client.UI.Dialogs.ConnectDialogResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ConnectDialogResult.html","topicUid":"EchoHub.Client.UI.Dialogs.ConnectDialogResult","type":"Class"},{"name":"CreateChannelDialog","href":"client/EchoHub.Client.UI.Dialogs.CreateChannelDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.CreateChannelDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.CreateChannelDialog","type":"Class"},{"name":"CreateChannelResult","href":"client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html","topicUid":"EchoHub.Client.UI.Dialogs.CreateChannelResult","type":"Class"},{"name":"ProfileAction","href":"client/EchoHub.Client.UI.Dialogs.ProfileAction.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ProfileAction.html","topicUid":"EchoHub.Client.UI.Dialogs.ProfileAction","type":"Enum"},{"name":"ProfileEditDialog","href":"client/EchoHub.Client.UI.Dialogs.ProfileEditDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ProfileEditDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.ProfileEditDialog","type":"Class"},{"name":"ProfileEditResult","href":"client/EchoHub.Client.UI.Dialogs.ProfileEditResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ProfileEditResult.html","topicUid":"EchoHub.Client.UI.Dialogs.ProfileEditResult","type":"Class"},{"name":"ProfileViewDialog","href":"client/EchoHub.Client.UI.Dialogs.ProfileViewDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ProfileViewDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.ProfileViewDialog","type":"Class"},{"name":"SearchDialog","href":"client/EchoHub.Client.UI.Dialogs.SearchDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.SearchDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.SearchDialog","type":"Class"},{"name":"SearchResult","href":"client/EchoHub.Client.UI.Dialogs.SearchResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.SearchResult.html","topicUid":"EchoHub.Client.UI.Dialogs.SearchResult","type":"Class"},{"name":"SearchResultType","href":"client/EchoHub.Client.UI.Dialogs.SearchResultType.html","topicHref":"client/EchoHub.Client.UI.Dialogs.SearchResultType.html","topicUid":"EchoHub.Client.UI.Dialogs.SearchResultType","type":"Enum"},{"name":"StatusDialog","href":"client/EchoHub.Client.UI.Dialogs.StatusDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.StatusDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.StatusDialog","type":"Class"},{"name":"StatusDialogResult","href":"client/EchoHub.Client.UI.Dialogs.StatusDialogResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.StatusDialogResult.html","topicUid":"EchoHub.Client.UI.Dialogs.StatusDialogResult","type":"Class"},{"name":"UpdateConfirmDialog","href":"client/EchoHub.Client.UI.Dialogs.UpdateConfirmDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.UpdateConfirmDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.UpdateConfirmDialog","type":"Class"},{"name":"UpdateProgressDialog","href":"client/EchoHub.Client.UI.Dialogs.UpdateProgressDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.UpdateProgressDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.UpdateProgressDialog","type":"Class"}]},{"name":"EchoHub.Client.UI.Helpers","href":"client/EchoHub.Client.UI.Helpers.html","topicHref":"client/EchoHub.Client.UI.Helpers.html","topicUid":"EchoHub.Client.UI.Helpers","type":"Namespace","items":[{"name":"EmojiHelper","href":"client/EchoHub.Client.UI.Helpers.EmojiHelper.html","topicHref":"client/EchoHub.Client.UI.Helpers.EmojiHelper.html","topicUid":"EchoHub.Client.UI.Helpers.EmojiHelper","type":"Class"},{"name":"HexColorHelper","href":"client/EchoHub.Client.UI.Helpers.HexColorHelper.html","topicHref":"client/EchoHub.Client.UI.Helpers.HexColorHelper.html","topicUid":"EchoHub.Client.UI.Helpers.HexColorHelper","type":"Class"}]},{"name":"EchoHub.Client.UI.ListSources","href":"client/EchoHub.Client.UI.ListSources.html","topicHref":"client/EchoHub.Client.UI.ListSources.html","topicUid":"EchoHub.Client.UI.ListSources","type":"Namespace","items":[{"name":"ChannelListSource","href":"client/EchoHub.Client.UI.ListSources.ChannelListSource.html","topicHref":"client/EchoHub.Client.UI.ListSources.ChannelListSource.html","topicUid":"EchoHub.Client.UI.ListSources.ChannelListSource","type":"Class"},{"name":"SearchListSource","href":"client/EchoHub.Client.UI.ListSources.SearchListSource.html","topicHref":"client/EchoHub.Client.UI.ListSources.SearchListSource.html","topicUid":"EchoHub.Client.UI.ListSources.SearchListSource","type":"Class"},{"name":"UserListSource","href":"client/EchoHub.Client.UI.ListSources.UserListSource.html","topicHref":"client/EchoHub.Client.UI.ListSources.UserListSource.html","topicUid":"EchoHub.Client.UI.ListSources.UserListSource","type":"Class"}]}]},{"name":"Articles","includedFrom":"~/api/client-articles/toc.yml","items":[{"name":"Overview","href":"client-articles/index.html","topicHref":"client-articles/index.html"}]}]},{"name":"Core","items":[{"name":"API Reference","includedFrom":"~/_api_meta/core/toc.yml","items":[{"name":"EchoHub.Core.Constants","href":"core/EchoHub.Core.Constants.html","topicHref":"core/EchoHub.Core.Constants.html","topicUid":"EchoHub.Core.Constants","type":"Namespace","items":[{"name":"HubConstants","href":"core/EchoHub.Core.Constants.HubConstants.html","topicHref":"core/EchoHub.Core.Constants.HubConstants.html","topicUid":"EchoHub.Core.Constants.HubConstants","type":"Class"},{"name":"ValidationConstants","href":"core/EchoHub.Core.Constants.ValidationConstants.html","topicHref":"core/EchoHub.Core.Constants.ValidationConstants.html","topicUid":"EchoHub.Core.Constants.ValidationConstants","type":"Class"}]},{"name":"EchoHub.Core.Contracts","href":"core/EchoHub.Core.Contracts.html","topicHref":"core/EchoHub.Core.Contracts.html","topicUid":"EchoHub.Core.Contracts","type":"Namespace","items":[{"name":"ChannelListItem","href":"core/EchoHub.Core.Contracts.ChannelListItem.html","topicHref":"core/EchoHub.Core.Contracts.ChannelListItem.html","topicUid":"EchoHub.Core.Contracts.ChannelListItem","type":"Class"},{"name":"IChannelService","href":"core/EchoHub.Core.Contracts.IChannelService.html","topicHref":"core/EchoHub.Core.Contracts.IChannelService.html","topicUid":"EchoHub.Core.Contracts.IChannelService","type":"Interface"},{"name":"IChatBroadcaster","href":"core/EchoHub.Core.Contracts.IChatBroadcaster.html","topicHref":"core/EchoHub.Core.Contracts.IChatBroadcaster.html","topicUid":"EchoHub.Core.Contracts.IChatBroadcaster","type":"Interface"},{"name":"IChatService","href":"core/EchoHub.Core.Contracts.IChatService.html","topicHref":"core/EchoHub.Core.Contracts.IChatService.html","topicUid":"EchoHub.Core.Contracts.IChatService","type":"Interface"},{"name":"IEchoHubClient","href":"core/EchoHub.Core.Contracts.IEchoHubClient.html","topicHref":"core/EchoHub.Core.Contracts.IEchoHubClient.html","topicUid":"EchoHub.Core.Contracts.IEchoHubClient","type":"Interface"},{"name":"IMessageEncryptionService","href":"core/EchoHub.Core.Contracts.IMessageEncryptionService.html","topicHref":"core/EchoHub.Core.Contracts.IMessageEncryptionService.html","topicUid":"EchoHub.Core.Contracts.IMessageEncryptionService","type":"Interface"},{"name":"IUserService","href":"core/EchoHub.Core.Contracts.IUserService.html","topicHref":"core/EchoHub.Core.Contracts.IUserService.html","topicUid":"EchoHub.Core.Contracts.IUserService","type":"Interface"}]},{"name":"EchoHub.Core.DTOs","href":"core/EchoHub.Core.DTOs.html","topicHref":"core/EchoHub.Core.DTOs.html","topicUid":"EchoHub.Core.DTOs","type":"Namespace","items":[{"name":"ApiResponse","href":"core/EchoHub.Core.DTOs.ApiResponse.html","topicHref":"core/EchoHub.Core.DTOs.ApiResponse.html","topicUid":"EchoHub.Core.DTOs.ApiResponse","type":"Class"},{"name":"ApiResponse","href":"core/EchoHub.Core.DTOs.ApiResponse-1.html","topicHref":"core/EchoHub.Core.DTOs.ApiResponse-1.html","topicUid":"EchoHub.Core.DTOs.ApiResponse`1","type":"Class"},{"name":"AssignRoleRequest","href":"core/EchoHub.Core.DTOs.AssignRoleRequest.html","topicHref":"core/EchoHub.Core.DTOs.AssignRoleRequest.html","topicUid":"EchoHub.Core.DTOs.AssignRoleRequest","type":"Class"},{"name":"AvatarUploadResponse","href":"core/EchoHub.Core.DTOs.AvatarUploadResponse.html","topicHref":"core/EchoHub.Core.DTOs.AvatarUploadResponse.html","topicUid":"EchoHub.Core.DTOs.AvatarUploadResponse","type":"Class"},{"name":"BanRequest","href":"core/EchoHub.Core.DTOs.BanRequest.html","topicHref":"core/EchoHub.Core.DTOs.BanRequest.html","topicUid":"EchoHub.Core.DTOs.BanRequest","type":"Class"},{"name":"ChannelDto","href":"core/EchoHub.Core.DTOs.ChannelDto.html","topicHref":"core/EchoHub.Core.DTOs.ChannelDto.html","topicUid":"EchoHub.Core.DTOs.ChannelDto","type":"Class"},{"name":"ChannelError","href":"core/EchoHub.Core.DTOs.ChannelError.html","topicHref":"core/EchoHub.Core.DTOs.ChannelError.html","topicUid":"EchoHub.Core.DTOs.ChannelError","type":"Enum"},{"name":"ChannelOperationResult","href":"core/EchoHub.Core.DTOs.ChannelOperationResult.html","topicHref":"core/EchoHub.Core.DTOs.ChannelOperationResult.html","topicUid":"EchoHub.Core.DTOs.ChannelOperationResult","type":"Class"},{"name":"CreateChannelRequest","href":"core/EchoHub.Core.DTOs.CreateChannelRequest.html","topicHref":"core/EchoHub.Core.DTOs.CreateChannelRequest.html","topicUid":"EchoHub.Core.DTOs.CreateChannelRequest","type":"Class"},{"name":"EmbedDto","href":"core/EchoHub.Core.DTOs.EmbedDto.html","topicHref":"core/EchoHub.Core.DTOs.EmbedDto.html","topicUid":"EchoHub.Core.DTOs.EmbedDto","type":"Class"},{"name":"EncryptionKeyResponse","href":"core/EchoHub.Core.DTOs.EncryptionKeyResponse.html","topicHref":"core/EchoHub.Core.DTOs.EncryptionKeyResponse.html","topicUid":"EchoHub.Core.DTOs.EncryptionKeyResponse","type":"Class"},{"name":"ErrorResponse","href":"core/EchoHub.Core.DTOs.ErrorResponse.html","topicHref":"core/EchoHub.Core.DTOs.ErrorResponse.html","topicUid":"EchoHub.Core.DTOs.ErrorResponse","type":"Class"},{"name":"JoinChannelResult","href":"core/EchoHub.Core.DTOs.JoinChannelResult.html","topicHref":"core/EchoHub.Core.DTOs.JoinChannelResult.html","topicUid":"EchoHub.Core.DTOs.JoinChannelResult","type":"Class"},{"name":"KickRequest","href":"core/EchoHub.Core.DTOs.KickRequest.html","topicHref":"core/EchoHub.Core.DTOs.KickRequest.html","topicUid":"EchoHub.Core.DTOs.KickRequest","type":"Class"},{"name":"LoginRequest","href":"core/EchoHub.Core.DTOs.LoginRequest.html","topicHref":"core/EchoHub.Core.DTOs.LoginRequest.html","topicUid":"EchoHub.Core.DTOs.LoginRequest","type":"Class"},{"name":"LoginResponse","href":"core/EchoHub.Core.DTOs.LoginResponse.html","topicHref":"core/EchoHub.Core.DTOs.LoginResponse.html","topicUid":"EchoHub.Core.DTOs.LoginResponse","type":"Class"},{"name":"MessageDto","href":"core/EchoHub.Core.DTOs.MessageDto.html","topicHref":"core/EchoHub.Core.DTOs.MessageDto.html","topicUid":"EchoHub.Core.DTOs.MessageDto","type":"Class"},{"name":"MuteRequest","href":"core/EchoHub.Core.DTOs.MuteRequest.html","topicHref":"core/EchoHub.Core.DTOs.MuteRequest.html","topicUid":"EchoHub.Core.DTOs.MuteRequest","type":"Class"},{"name":"PaginatedResponse","href":"core/EchoHub.Core.DTOs.PaginatedResponse-1.html","topicHref":"core/EchoHub.Core.DTOs.PaginatedResponse-1.html","topicUid":"EchoHub.Core.DTOs.PaginatedResponse`1","type":"Class"},{"name":"RefreshRequest","href":"core/EchoHub.Core.DTOs.RefreshRequest.html","topicHref":"core/EchoHub.Core.DTOs.RefreshRequest.html","topicUid":"EchoHub.Core.DTOs.RefreshRequest","type":"Class"},{"name":"RegisterRequest","href":"core/EchoHub.Core.DTOs.RegisterRequest.html","topicHref":"core/EchoHub.Core.DTOs.RegisterRequest.html","topicUid":"EchoHub.Core.DTOs.RegisterRequest","type":"Class"},{"name":"SendMessageRequest","href":"core/EchoHub.Core.DTOs.SendMessageRequest.html","topicHref":"core/EchoHub.Core.DTOs.SendMessageRequest.html","topicUid":"EchoHub.Core.DTOs.SendMessageRequest","type":"Class"},{"name":"SendUrlRequest","href":"core/EchoHub.Core.DTOs.SendUrlRequest.html","topicHref":"core/EchoHub.Core.DTOs.SendUrlRequest.html","topicUid":"EchoHub.Core.DTOs.SendUrlRequest","type":"Class"},{"name":"ServerStatusDto","href":"core/EchoHub.Core.DTOs.ServerStatusDto.html","topicHref":"core/EchoHub.Core.DTOs.ServerStatusDto.html","topicUid":"EchoHub.Core.DTOs.ServerStatusDto","type":"Class"},{"name":"UpdateProfileRequest","href":"core/EchoHub.Core.DTOs.UpdateProfileRequest.html","topicHref":"core/EchoHub.Core.DTOs.UpdateProfileRequest.html","topicUid":"EchoHub.Core.DTOs.UpdateProfileRequest","type":"Class"},{"name":"UpdateStatusRequest","href":"core/EchoHub.Core.DTOs.UpdateStatusRequest.html","topicHref":"core/EchoHub.Core.DTOs.UpdateStatusRequest.html","topicUid":"EchoHub.Core.DTOs.UpdateStatusRequest","type":"Class"},{"name":"UpdateTopicRequest","href":"core/EchoHub.Core.DTOs.UpdateTopicRequest.html","topicHref":"core/EchoHub.Core.DTOs.UpdateTopicRequest.html","topicUid":"EchoHub.Core.DTOs.UpdateTopicRequest","type":"Class"},{"name":"UserDto","href":"core/EchoHub.Core.DTOs.UserDto.html","topicHref":"core/EchoHub.Core.DTOs.UserDto.html","topicUid":"EchoHub.Core.DTOs.UserDto","type":"Class"},{"name":"UserError","href":"core/EchoHub.Core.DTOs.UserError.html","topicHref":"core/EchoHub.Core.DTOs.UserError.html","topicUid":"EchoHub.Core.DTOs.UserError","type":"Enum"},{"name":"UserOperationResult","href":"core/EchoHub.Core.DTOs.UserOperationResult.html","topicHref":"core/EchoHub.Core.DTOs.UserOperationResult.html","topicUid":"EchoHub.Core.DTOs.UserOperationResult","type":"Class"},{"name":"UserPresenceDto","href":"core/EchoHub.Core.DTOs.UserPresenceDto.html","topicHref":"core/EchoHub.Core.DTOs.UserPresenceDto.html","topicUid":"EchoHub.Core.DTOs.UserPresenceDto","type":"Class"},{"name":"UserProfileDto","href":"core/EchoHub.Core.DTOs.UserProfileDto.html","topicHref":"core/EchoHub.Core.DTOs.UserProfileDto.html","topicUid":"EchoHub.Core.DTOs.UserProfileDto","type":"Class"}]},{"name":"EchoHub.Core.Models","href":"core/EchoHub.Core.Models.html","topicHref":"core/EchoHub.Core.Models.html","topicUid":"EchoHub.Core.Models","type":"Namespace","items":[{"name":"Channel","href":"core/EchoHub.Core.Models.Channel.html","topicHref":"core/EchoHub.Core.Models.Channel.html","topicUid":"EchoHub.Core.Models.Channel","type":"Class"},{"name":"ChannelMembership","href":"core/EchoHub.Core.Models.ChannelMembership.html","topicHref":"core/EchoHub.Core.Models.ChannelMembership.html","topicUid":"EchoHub.Core.Models.ChannelMembership","type":"Class"},{"name":"Message","href":"core/EchoHub.Core.Models.Message.html","topicHref":"core/EchoHub.Core.Models.Message.html","topicUid":"EchoHub.Core.Models.Message","type":"Class"},{"name":"MessageType","href":"core/EchoHub.Core.Models.MessageType.html","topicHref":"core/EchoHub.Core.Models.MessageType.html","topicUid":"EchoHub.Core.Models.MessageType","type":"Enum"},{"name":"RefreshToken","href":"core/EchoHub.Core.Models.RefreshToken.html","topicHref":"core/EchoHub.Core.Models.RefreshToken.html","topicUid":"EchoHub.Core.Models.RefreshToken","type":"Class"},{"name":"ServerRole","href":"core/EchoHub.Core.Models.ServerRole.html","topicHref":"core/EchoHub.Core.Models.ServerRole.html","topicUid":"EchoHub.Core.Models.ServerRole","type":"Enum"},{"name":"User","href":"core/EchoHub.Core.Models.User.html","topicHref":"core/EchoHub.Core.Models.User.html","topicUid":"EchoHub.Core.Models.User","type":"Class"},{"name":"UserStatus","href":"core/EchoHub.Core.Models.UserStatus.html","topicHref":"core/EchoHub.Core.Models.UserStatus.html","topicUid":"EchoHub.Core.Models.UserStatus","type":"Enum"}]}]},{"name":"Articles","includedFrom":"~/api/core-articles/toc.yml","items":[{"name":"Overview","href":"core-articles/index.html","topicHref":"core-articles/index.html"}]}]},{"name":"Server","items":[{"name":"API Reference","includedFrom":"~/_api_meta/server/toc.yml","items":[{"name":"EchoHub.Server.Auth","href":"server/EchoHub.Server.Auth.html","topicHref":"server/EchoHub.Server.Auth.html","topicUid":"EchoHub.Server.Auth","type":"Namespace","items":[{"name":"JwtTokenService","href":"server/EchoHub.Server.Auth.JwtTokenService.html","topicHref":"server/EchoHub.Server.Auth.JwtTokenService.html","topicUid":"EchoHub.Server.Auth.JwtTokenService","type":"Class"}]},{"name":"EchoHub.Server.Controllers","href":"server/EchoHub.Server.Controllers.html","topicHref":"server/EchoHub.Server.Controllers.html","topicUid":"EchoHub.Server.Controllers","type":"Namespace","items":[{"name":"AuthController","href":"server/EchoHub.Server.Controllers.AuthController.html","topicHref":"server/EchoHub.Server.Controllers.AuthController.html","topicUid":"EchoHub.Server.Controllers.AuthController","type":"Class"},{"name":"ChannelsController","href":"server/EchoHub.Server.Controllers.ChannelsController.html","topicHref":"server/EchoHub.Server.Controllers.ChannelsController.html","topicUid":"EchoHub.Server.Controllers.ChannelsController","type":"Class"},{"name":"FilesController","href":"server/EchoHub.Server.Controllers.FilesController.html","topicHref":"server/EchoHub.Server.Controllers.FilesController.html","topicUid":"EchoHub.Server.Controllers.FilesController","type":"Class"},{"name":"ModerationController","href":"server/EchoHub.Server.Controllers.ModerationController.html","topicHref":"server/EchoHub.Server.Controllers.ModerationController.html","topicUid":"EchoHub.Server.Controllers.ModerationController","type":"Class"},{"name":"ServerController","href":"server/EchoHub.Server.Controllers.ServerController.html","topicHref":"server/EchoHub.Server.Controllers.ServerController.html","topicUid":"EchoHub.Server.Controllers.ServerController","type":"Class"},{"name":"UsersController","href":"server/EchoHub.Server.Controllers.UsersController.html","topicHref":"server/EchoHub.Server.Controllers.UsersController.html","topicUid":"EchoHub.Server.Controllers.UsersController","type":"Class"}]},{"name":"EchoHub.Server.Data","href":"server/EchoHub.Server.Data.html","topicHref":"server/EchoHub.Server.Data.html","topicUid":"EchoHub.Server.Data","type":"Namespace","items":[{"name":"EchoHubDbContext","href":"server/EchoHub.Server.Data.EchoHubDbContext.html","topicHref":"server/EchoHub.Server.Data.EchoHubDbContext.html","topicUid":"EchoHub.Server.Data.EchoHubDbContext","type":"Class"}]},{"name":"EchoHub.Server.Data.Migrations","href":"server/EchoHub.Server.Data.Migrations.html","topicHref":"server/EchoHub.Server.Data.Migrations.html","topicUid":"EchoHub.Server.Data.Migrations","type":"Namespace","items":[{"name":"AddAttachmentFileSize","href":"server/EchoHub.Server.Data.Migrations.AddAttachmentFileSize.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddAttachmentFileSize.html","topicUid":"EchoHub.Server.Data.Migrations.AddAttachmentFileSize","type":"Class"},{"name":"AddChannelIsPublic","href":"server/EchoHub.Server.Data.Migrations.AddChannelIsPublic.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddChannelIsPublic.html","topicUid":"EchoHub.Server.Data.Migrations.AddChannelIsPublic","type":"Class"},{"name":"AddChannelMembership","href":"server/EchoHub.Server.Data.Migrations.AddChannelMembership.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddChannelMembership.html","topicUid":"EchoHub.Server.Data.Migrations.AddChannelMembership","type":"Class"},{"name":"AddEncryptionSupport","href":"server/EchoHub.Server.Data.Migrations.AddEncryptionSupport.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddEncryptionSupport.html","topicUid":"EchoHub.Server.Data.Migrations.AddEncryptionSupport","type":"Class"},{"name":"AddMessageEmbed","href":"server/EchoHub.Server.Data.Migrations.AddMessageEmbed.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddMessageEmbed.html","topicUid":"EchoHub.Server.Data.Migrations.AddMessageEmbed","type":"Class"},{"name":"AddModerationRoles","href":"server/EchoHub.Server.Data.Migrations.AddModerationRoles.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddModerationRoles.html","topicUid":"EchoHub.Server.Data.Migrations.AddModerationRoles","type":"Class"},{"name":"InitialCreate","href":"server/EchoHub.Server.Data.Migrations.InitialCreate.html","topicHref":"server/EchoHub.Server.Data.Migrations.InitialCreate.html","topicUid":"EchoHub.Server.Data.Migrations.InitialCreate","type":"Class"}]},{"name":"EchoHub.Server.Hubs","href":"server/EchoHub.Server.Hubs.html","topicHref":"server/EchoHub.Server.Hubs.html","topicUid":"EchoHub.Server.Hubs","type":"Namespace","items":[{"name":"ChatHub","href":"server/EchoHub.Server.Hubs.ChatHub.html","topicHref":"server/EchoHub.Server.Hubs.ChatHub.html","topicUid":"EchoHub.Server.Hubs.ChatHub","type":"Class"}]},{"name":"EchoHub.Server.Services","href":"server/EchoHub.Server.Services.html","topicHref":"server/EchoHub.Server.Services.html","topicUid":"EchoHub.Server.Services","type":"Namespace","items":[{"name":"ChannelService","href":"server/EchoHub.Server.Services.ChannelService.html","topicHref":"server/EchoHub.Server.Services.ChannelService.html","topicUid":"EchoHub.Server.Services.ChannelService","type":"Class"},{"name":"ChatService","href":"server/EchoHub.Server.Services.ChatService.html","topicHref":"server/EchoHub.Server.Services.ChatService.html","topicUid":"EchoHub.Server.Services.ChatService","type":"Class"},{"name":"DirectoryClaimStore","href":"server/EchoHub.Server.Services.DirectoryClaimStore.html","topicHref":"server/EchoHub.Server.Services.DirectoryClaimStore.html","topicUid":"EchoHub.Server.Services.DirectoryClaimStore","type":"Class"},{"name":"FileCleanupService","href":"server/EchoHub.Server.Services.FileCleanupService.html","topicHref":"server/EchoHub.Server.Services.FileCleanupService.html","topicUid":"EchoHub.Server.Services.FileCleanupService","type":"Class"},{"name":"FileStorageService","href":"server/EchoHub.Server.Services.FileStorageService.html","topicHref":"server/EchoHub.Server.Services.FileStorageService.html","topicUid":"EchoHub.Server.Services.FileStorageService","type":"Class"},{"name":"FileValidationHelper","href":"server/EchoHub.Server.Services.FileValidationHelper.html","topicHref":"server/EchoHub.Server.Services.FileValidationHelper.html","topicUid":"EchoHub.Server.Services.FileValidationHelper","type":"Class"},{"name":"ImageToAsciiService","href":"server/EchoHub.Server.Services.ImageToAsciiService.html","topicHref":"server/EchoHub.Server.Services.ImageToAsciiService.html","topicUid":"EchoHub.Server.Services.ImageToAsciiService","type":"Class"},{"name":"LinkEmbedService","href":"server/EchoHub.Server.Services.LinkEmbedService.html","topicHref":"server/EchoHub.Server.Services.LinkEmbedService.html","topicUid":"EchoHub.Server.Services.LinkEmbedService","type":"Class"},{"name":"MessageEncryptionService","href":"server/EchoHub.Server.Services.MessageEncryptionService.html","topicHref":"server/EchoHub.Server.Services.MessageEncryptionService.html","topicUid":"EchoHub.Server.Services.MessageEncryptionService","type":"Class"},{"name":"MuteExpirationService","href":"server/EchoHub.Server.Services.MuteExpirationService.html","topicHref":"server/EchoHub.Server.Services.MuteExpirationService.html","topicUid":"EchoHub.Server.Services.MuteExpirationService","type":"Class"},{"name":"PresenceTracker","href":"server/EchoHub.Server.Services.PresenceTracker.html","topicHref":"server/EchoHub.Server.Services.PresenceTracker.html","topicUid":"EchoHub.Server.Services.PresenceTracker","type":"Class"},{"name":"RegistrationStatus","href":"server/EchoHub.Server.Services.RegistrationStatus.html","topicHref":"server/EchoHub.Server.Services.RegistrationStatus.html","topicUid":"EchoHub.Server.Services.RegistrationStatus","type":"Class"},{"name":"ServerDirectoryService","href":"server/EchoHub.Server.Services.ServerDirectoryService.html","topicHref":"server/EchoHub.Server.Services.ServerDirectoryService.html","topicUid":"EchoHub.Server.Services.ServerDirectoryService","type":"Class"},{"name":"SignalRBroadcaster","href":"server/EchoHub.Server.Services.SignalRBroadcaster.html","topicHref":"server/EchoHub.Server.Services.SignalRBroadcaster.html","topicUid":"EchoHub.Server.Services.SignalRBroadcaster","type":"Class"},{"name":"UserService","href":"server/EchoHub.Server.Services.UserService.html","topicHref":"server/EchoHub.Server.Services.UserService.html","topicUid":"EchoHub.Server.Services.UserService","type":"Class"}]},{"name":"EchoHub.Server.Setup","href":"server/EchoHub.Server.Setup.html","topicHref":"server/EchoHub.Server.Setup.html","topicUid":"EchoHub.Server.Setup","type":"Namespace","items":[{"name":"DataMigrationService","href":"server/EchoHub.Server.Setup.DataMigrationService.html","topicHref":"server/EchoHub.Server.Setup.DataMigrationService.html","topicUid":"EchoHub.Server.Setup.DataMigrationService","type":"Class"},{"name":"DatabaseSetup","href":"server/EchoHub.Server.Setup.DatabaseSetup.html","topicHref":"server/EchoHub.Server.Setup.DatabaseSetup.html","topicUid":"EchoHub.Server.Setup.DatabaseSetup","type":"Class"},{"name":"FirstRunSetup","href":"server/EchoHub.Server.Setup.FirstRunSetup.html","topicHref":"server/EchoHub.Server.Setup.FirstRunSetup.html","topicUid":"EchoHub.Server.Setup.FirstRunSetup","type":"Class"}]}]},{"name":"Articles","includedFrom":"~/api/server-articles/toc.yml","items":[{"name":"Overview","href":"server-articles/index.html","topicHref":"server-articles/index.html"}]}]},{"name":"Server.Irc","items":[{"name":"API Reference","includedFrom":"~/_api_meta/server-irc/toc.yml","items":[{"name":"EchoHub.Server.Irc","href":"server-irc/EchoHub.Server.Irc.html","topicHref":"server-irc/EchoHub.Server.Irc.html","topicUid":"EchoHub.Server.Irc","type":"Namespace","items":[{"name":"IrcBroadcaster","href":"server-irc/EchoHub.Server.Irc.IrcBroadcaster.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcBroadcaster.html","topicUid":"EchoHub.Server.Irc.IrcBroadcaster","type":"Class"},{"name":"IrcClientConnection","href":"server-irc/EchoHub.Server.Irc.IrcClientConnection.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcClientConnection.html","topicUid":"EchoHub.Server.Irc.IrcClientConnection","type":"Class"},{"name":"IrcCommandHandler","href":"server-irc/EchoHub.Server.Irc.IrcCommandHandler.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcCommandHandler.html","topicUid":"EchoHub.Server.Irc.IrcCommandHandler","type":"Class"},{"name":"IrcGatewayService","href":"server-irc/EchoHub.Server.Irc.IrcGatewayService.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcGatewayService.html","topicUid":"EchoHub.Server.Irc.IrcGatewayService","type":"Class"},{"name":"IrcMessage","href":"server-irc/EchoHub.Server.Irc.IrcMessage.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcMessage.html","topicUid":"EchoHub.Server.Irc.IrcMessage","type":"Class"},{"name":"IrcMessageFormatter","href":"server-irc/EchoHub.Server.Irc.IrcMessageFormatter.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcMessageFormatter.html","topicUid":"EchoHub.Server.Irc.IrcMessageFormatter","type":"Class"},{"name":"IrcNumericReply","href":"server-irc/EchoHub.Server.Irc.IrcNumericReply.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcNumericReply.html","topicUid":"EchoHub.Server.Irc.IrcNumericReply","type":"Class"},{"name":"IrcOptions","href":"server-irc/EchoHub.Server.Irc.IrcOptions.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcOptions.html","topicUid":"EchoHub.Server.Irc.IrcOptions","type":"Class"},{"name":"IrcServiceExtensions","href":"server-irc/EchoHub.Server.Irc.IrcServiceExtensions.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcServiceExtensions.html","topicUid":"EchoHub.Server.Irc.IrcServiceExtensions","type":"Class"}]}]}]}]}
+{"items":[{"name":"Client","items":[{"name":"API Reference","includedFrom":"~/_api_meta/client/toc.yml","items":[{"name":"EchoHub.Client","href":"client/EchoHub.Client.html","topicHref":"client/EchoHub.Client.html","topicUid":"EchoHub.Client","type":"Namespace","items":[{"name":"AppOrchestrator","href":"client/EchoHub.Client.AppOrchestrator.html","topicHref":"client/EchoHub.Client.AppOrchestrator.html","topicUid":"EchoHub.Client.AppOrchestrator","type":"Class"}]},{"name":"EchoHub.Client.Commands","href":"client/EchoHub.Client.Commands.html","topicHref":"client/EchoHub.Client.Commands.html","topicUid":"EchoHub.Client.Commands","type":"Namespace","items":[{"name":"CommandHandler","href":"client/EchoHub.Client.Commands.CommandHandler.html","topicHref":"client/EchoHub.Client.Commands.CommandHandler.html","topicUid":"EchoHub.Client.Commands.CommandHandler","type":"Class"},{"name":"CommandResult","href":"client/EchoHub.Client.Commands.CommandResult.html","topicHref":"client/EchoHub.Client.Commands.CommandResult.html","topicUid":"EchoHub.Client.Commands.CommandResult","type":"Class"}]},{"name":"EchoHub.Client.Config","href":"client/EchoHub.Client.Config.html","topicHref":"client/EchoHub.Client.Config.html","topicUid":"EchoHub.Client.Config","type":"Namespace","items":[{"name":"AccountPreset","href":"client/EchoHub.Client.Config.AccountPreset.html","topicHref":"client/EchoHub.Client.Config.AccountPreset.html","topicUid":"EchoHub.Client.Config.AccountPreset","type":"Class"},{"name":"ClientConfig","href":"client/EchoHub.Client.Config.ClientConfig.html","topicHref":"client/EchoHub.Client.Config.ClientConfig.html","topicUid":"EchoHub.Client.Config.ClientConfig","type":"Class"},{"name":"ConfigManager","href":"client/EchoHub.Client.Config.ConfigManager.html","topicHref":"client/EchoHub.Client.Config.ConfigManager.html","topicUid":"EchoHub.Client.Config.ConfigManager","type":"Class"},{"name":"NotificationConfig","href":"client/EchoHub.Client.Config.NotificationConfig.html","topicHref":"client/EchoHub.Client.Config.NotificationConfig.html","topicUid":"EchoHub.Client.Config.NotificationConfig","type":"Class"},{"name":"SavedServer","href":"client/EchoHub.Client.Config.SavedServer.html","topicHref":"client/EchoHub.Client.Config.SavedServer.html","topicUid":"EchoHub.Client.Config.SavedServer","type":"Class"}]},{"name":"EchoHub.Client.Services","href":"client/EchoHub.Client.Services.html","topicHref":"client/EchoHub.Client.Services.html","topicUid":"EchoHub.Client.Services","type":"Namespace","items":[{"name":"ApiClient","href":"client/EchoHub.Client.Services.ApiClient.html","topicHref":"client/EchoHub.Client.Services.ApiClient.html","topicUid":"EchoHub.Client.Services.ApiClient","type":"Class"},{"name":"AsyncRunner","href":"client/EchoHub.Client.Services.AsyncRunner.html","topicHref":"client/EchoHub.Client.Services.AsyncRunner.html","topicUid":"EchoHub.Client.Services.AsyncRunner","type":"Class"},{"name":"AudioPlaybackService","href":"client/EchoHub.Client.Services.AudioPlaybackService.html","topicHref":"client/EchoHub.Client.Services.AudioPlaybackService.html","topicUid":"EchoHub.Client.Services.AudioPlaybackService","type":"Class"},{"name":"BackupInfo","href":"client/EchoHub.Client.Services.BackupInfo.html","topicHref":"client/EchoHub.Client.Services.BackupInfo.html","topicUid":"EchoHub.Client.Services.BackupInfo","type":"Class"},{"name":"ChannelPasswordRequiredException","href":"client/EchoHub.Client.Services.ChannelPasswordRequiredException.html","topicHref":"client/EchoHub.Client.Services.ChannelPasswordRequiredException.html","topicUid":"EchoHub.Client.Services.ChannelPasswordRequiredException","type":"Class"},{"name":"ClientEncryptionService","href":"client/EchoHub.Client.Services.ClientEncryptionService.html","topicHref":"client/EchoHub.Client.Services.ClientEncryptionService.html","topicUid":"EchoHub.Client.Services.ClientEncryptionService","type":"Class"},{"name":"ClipboardFiles","href":"client/EchoHub.Client.Services.ClipboardFiles.html","topicHref":"client/EchoHub.Client.Services.ClipboardFiles.html","topicUid":"EchoHub.Client.Services.ClipboardFiles","type":"Class"},{"name":"EchoHubConnection","href":"client/EchoHub.Client.Services.EchoHubConnection.html","topicHref":"client/EchoHub.Client.Services.EchoHubConnection.html","topicUid":"EchoHub.Client.Services.EchoHubConnection","type":"Class"},{"name":"FolderPickResult","href":"client/EchoHub.Client.Services.FolderPickResult.html","topicHref":"client/EchoHub.Client.Services.FolderPickResult.html","topicUid":"EchoHub.Client.Services.FolderPickResult","type":"Class"},{"name":"JoinOutcome","href":"client/EchoHub.Client.Services.JoinOutcome.html","topicHref":"client/EchoHub.Client.Services.JoinOutcome.html","topicUid":"EchoHub.Client.Services.JoinOutcome","type":"Class"},{"name":"NativeFolderPicker","href":"client/EchoHub.Client.Services.NativeFolderPicker.html","topicHref":"client/EchoHub.Client.Services.NativeFolderPicker.html","topicUid":"EchoHub.Client.Services.NativeFolderPicker","type":"Class"},{"name":"NotificationSoundService","href":"client/EchoHub.Client.Services.NotificationSoundService.html","topicHref":"client/EchoHub.Client.Services.NotificationSoundService.html","topicUid":"EchoHub.Client.Services.NotificationSoundService","type":"Class"},{"name":"OutgoingAttachment","href":"client/EchoHub.Client.Services.OutgoingAttachment.html","topicHref":"client/EchoHub.Client.Services.OutgoingAttachment.html","topicUid":"EchoHub.Client.Services.OutgoingAttachment","type":"Class"},{"name":"PathSetup","href":"client/EchoHub.Client.Services.PathSetup.html","topicHref":"client/EchoHub.Client.Services.PathSetup.html","topicUid":"EchoHub.Client.Services.PathSetup","type":"Class"},{"name":"PickerOutcome","href":"client/EchoHub.Client.Services.PickerOutcome.html","topicHref":"client/EchoHub.Client.Services.PickerOutcome.html","topicUid":"EchoHub.Client.Services.PickerOutcome","type":"Enum"},{"name":"RoomKeyStore","href":"client/EchoHub.Client.Services.RoomKeyStore.html","topicHref":"client/EchoHub.Client.Services.RoomKeyStore.html","topicUid":"EchoHub.Client.Services.RoomKeyStore","type":"Class"},{"name":"UpdateBackupService","href":"client/EchoHub.Client.Services.UpdateBackupService.html","topicHref":"client/EchoHub.Client.Services.UpdateBackupService.html","topicUid":"EchoHub.Client.Services.UpdateBackupService","type":"Class"},{"name":"UpdateChecker","href":"client/EchoHub.Client.Services.UpdateChecker.html","topicHref":"client/EchoHub.Client.Services.UpdateChecker.html","topicUid":"EchoHub.Client.Services.UpdateChecker","type":"Class"}]},{"name":"EchoHub.Client.Themes","href":"client/EchoHub.Client.Themes.html","topicHref":"client/EchoHub.Client.Themes.html","topicUid":"EchoHub.Client.Themes","type":"Namespace","items":[{"name":"Theme","href":"client/EchoHub.Client.Themes.Theme.html","topicHref":"client/EchoHub.Client.Themes.Theme.html","topicUid":"EchoHub.Client.Themes.Theme","type":"Class"},{"name":"ThemeColors","href":"client/EchoHub.Client.Themes.ThemeColors.html","topicHref":"client/EchoHub.Client.Themes.ThemeColors.html","topicUid":"EchoHub.Client.Themes.ThemeColors","type":"Class"},{"name":"ThemeManager","href":"client/EchoHub.Client.Themes.ThemeManager.html","topicHref":"client/EchoHub.Client.Themes.ThemeManager.html","topicUid":"EchoHub.Client.Themes.ThemeManager","type":"Class"}]},{"name":"EchoHub.Client.UI","href":"client/EchoHub.Client.UI.html","topicHref":"client/EchoHub.Client.UI.html","topicUid":"EchoHub.Client.UI","type":"Namespace","items":[{"name":"MainWindow","href":"client/EchoHub.Client.UI.MainWindow.html","topicHref":"client/EchoHub.Client.UI.MainWindow.html","topicUid":"EchoHub.Client.UI.MainWindow","type":"Class"}]},{"name":"EchoHub.Client.UI.Chat","href":"client/EchoHub.Client.UI.Chat.html","topicHref":"client/EchoHub.Client.UI.Chat.html","topicUid":"EchoHub.Client.UI.Chat","type":"Namespace","items":[{"name":"ChatColors","href":"client/EchoHub.Client.UI.Chat.ChatColors.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatColors.html","topicUid":"EchoHub.Client.UI.Chat.ChatColors","type":"Class"},{"name":"ChatLine","href":"client/EchoHub.Client.UI.Chat.ChatLine.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatLine.html","topicUid":"EchoHub.Client.UI.Chat.ChatLine","type":"Class"},{"name":"ChatListSource","href":"client/EchoHub.Client.UI.Chat.ChatListSource.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatListSource.html","topicUid":"EchoHub.Client.UI.Chat.ChatListSource","type":"Class"},{"name":"ChatMessageManager","href":"client/EchoHub.Client.UI.Chat.ChatMessageManager.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatMessageManager.html","topicUid":"EchoHub.Client.UI.Chat.ChatMessageManager","type":"Class"},{"name":"ChatSegment","href":"client/EchoHub.Client.UI.Chat.ChatSegment.html","topicHref":"client/EchoHub.Client.UI.Chat.ChatSegment.html","topicUid":"EchoHub.Client.UI.Chat.ChatSegment","type":"Class"}]},{"name":"EchoHub.Client.UI.Dialogs","href":"client/EchoHub.Client.UI.Dialogs.html","topicHref":"client/EchoHub.Client.UI.Dialogs.html","topicUid":"EchoHub.Client.UI.Dialogs","type":"Namespace","items":[{"name":"AudioPlayerDialog","href":"client/EchoHub.Client.UI.Dialogs.AudioPlayerDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.AudioPlayerDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.AudioPlayerDialog","type":"Class"},{"name":"ChannelPasswordDialog","href":"client/EchoHub.Client.UI.Dialogs.ChannelPasswordDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ChannelPasswordDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.ChannelPasswordDialog","type":"Class"},{"name":"ConnectDialog","href":"client/EchoHub.Client.UI.Dialogs.ConnectDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ConnectDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.ConnectDialog","type":"Class"},{"name":"ConnectDialogResult","href":"client/EchoHub.Client.UI.Dialogs.ConnectDialogResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ConnectDialogResult.html","topicUid":"EchoHub.Client.UI.Dialogs.ConnectDialogResult","type":"Class"},{"name":"CreateChannelDialog","href":"client/EchoHub.Client.UI.Dialogs.CreateChannelDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.CreateChannelDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.CreateChannelDialog","type":"Class"},{"name":"CreateChannelResult","href":"client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.CreateChannelResult.html","topicUid":"EchoHub.Client.UI.Dialogs.CreateChannelResult","type":"Class"},{"name":"ProfileAction","href":"client/EchoHub.Client.UI.Dialogs.ProfileAction.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ProfileAction.html","topicUid":"EchoHub.Client.UI.Dialogs.ProfileAction","type":"Enum"},{"name":"ProfileEditDialog","href":"client/EchoHub.Client.UI.Dialogs.ProfileEditDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ProfileEditDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.ProfileEditDialog","type":"Class"},{"name":"ProfileEditResult","href":"client/EchoHub.Client.UI.Dialogs.ProfileEditResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ProfileEditResult.html","topicUid":"EchoHub.Client.UI.Dialogs.ProfileEditResult","type":"Class"},{"name":"ProfileViewDialog","href":"client/EchoHub.Client.UI.Dialogs.ProfileViewDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.ProfileViewDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.ProfileViewDialog","type":"Class"},{"name":"SearchDialog","href":"client/EchoHub.Client.UI.Dialogs.SearchDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.SearchDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.SearchDialog","type":"Class"},{"name":"SearchResult","href":"client/EchoHub.Client.UI.Dialogs.SearchResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.SearchResult.html","topicUid":"EchoHub.Client.UI.Dialogs.SearchResult","type":"Class"},{"name":"SearchResultType","href":"client/EchoHub.Client.UI.Dialogs.SearchResultType.html","topicHref":"client/EchoHub.Client.UI.Dialogs.SearchResultType.html","topicUid":"EchoHub.Client.UI.Dialogs.SearchResultType","type":"Enum"},{"name":"StatusDialog","href":"client/EchoHub.Client.UI.Dialogs.StatusDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.StatusDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.StatusDialog","type":"Class"},{"name":"StatusDialogResult","href":"client/EchoHub.Client.UI.Dialogs.StatusDialogResult.html","topicHref":"client/EchoHub.Client.UI.Dialogs.StatusDialogResult.html","topicUid":"EchoHub.Client.UI.Dialogs.StatusDialogResult","type":"Class"},{"name":"UpdateConfirmDialog","href":"client/EchoHub.Client.UI.Dialogs.UpdateConfirmDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.UpdateConfirmDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.UpdateConfirmDialog","type":"Class"},{"name":"UpdateProgressDialog","href":"client/EchoHub.Client.UI.Dialogs.UpdateProgressDialog.html","topicHref":"client/EchoHub.Client.UI.Dialogs.UpdateProgressDialog.html","topicUid":"EchoHub.Client.UI.Dialogs.UpdateProgressDialog","type":"Class"}]},{"name":"EchoHub.Client.UI.Helpers","href":"client/EchoHub.Client.UI.Helpers.html","topicHref":"client/EchoHub.Client.UI.Helpers.html","topicUid":"EchoHub.Client.UI.Helpers","type":"Namespace","items":[{"name":"DroppedFileParser","href":"client/EchoHub.Client.UI.Helpers.DroppedFileParser.html","topicHref":"client/EchoHub.Client.UI.Helpers.DroppedFileParser.html","topicUid":"EchoHub.Client.UI.Helpers.DroppedFileParser","type":"Class"},{"name":"EmojiHelper","href":"client/EchoHub.Client.UI.Helpers.EmojiHelper.html","topicHref":"client/EchoHub.Client.UI.Helpers.EmojiHelper.html","topicUid":"EchoHub.Client.UI.Helpers.EmojiHelper","type":"Class"},{"name":"HexColorHelper","href":"client/EchoHub.Client.UI.Helpers.HexColorHelper.html","topicHref":"client/EchoHub.Client.UI.Helpers.HexColorHelper.html","topicUid":"EchoHub.Client.UI.Helpers.HexColorHelper","type":"Class"}]},{"name":"EchoHub.Client.UI.ListSources","href":"client/EchoHub.Client.UI.ListSources.html","topicHref":"client/EchoHub.Client.UI.ListSources.html","topicUid":"EchoHub.Client.UI.ListSources","type":"Namespace","items":[{"name":"ChannelListSource","href":"client/EchoHub.Client.UI.ListSources.ChannelListSource.html","topicHref":"client/EchoHub.Client.UI.ListSources.ChannelListSource.html","topicUid":"EchoHub.Client.UI.ListSources.ChannelListSource","type":"Class"},{"name":"SearchListSource","href":"client/EchoHub.Client.UI.ListSources.SearchListSource.html","topicHref":"client/EchoHub.Client.UI.ListSources.SearchListSource.html","topicUid":"EchoHub.Client.UI.ListSources.SearchListSource","type":"Class"},{"name":"UserListSource","href":"client/EchoHub.Client.UI.ListSources.UserListSource.html","topicHref":"client/EchoHub.Client.UI.ListSources.UserListSource.html","topicUid":"EchoHub.Client.UI.ListSources.UserListSource","type":"Class"}]}]},{"name":"Articles","includedFrom":"~/api/client-articles/toc.yml","items":[{"name":"Overview","href":"client-articles/index.html","topicHref":"client-articles/index.html"}]}]},{"name":"Core","items":[{"name":"API Reference","includedFrom":"~/_api_meta/core/toc.yml","items":[{"name":"EchoHub.Core.Constants","href":"core/EchoHub.Core.Constants.html","topicHref":"core/EchoHub.Core.Constants.html","topicUid":"EchoHub.Core.Constants","type":"Namespace","items":[{"name":"HubConstants","href":"core/EchoHub.Core.Constants.HubConstants.html","topicHref":"core/EchoHub.Core.Constants.HubConstants.html","topicUid":"EchoHub.Core.Constants.HubConstants","type":"Class"},{"name":"ValidationConstants","href":"core/EchoHub.Core.Constants.ValidationConstants.html","topicHref":"core/EchoHub.Core.Constants.ValidationConstants.html","topicUid":"EchoHub.Core.Constants.ValidationConstants","type":"Class"}]},{"name":"EchoHub.Core.Contracts","href":"core/EchoHub.Core.Contracts.html","topicHref":"core/EchoHub.Core.Contracts.html","topicUid":"EchoHub.Core.Contracts","type":"Namespace","items":[{"name":"ChannelListItem","href":"core/EchoHub.Core.Contracts.ChannelListItem.html","topicHref":"core/EchoHub.Core.Contracts.ChannelListItem.html","topicUid":"EchoHub.Core.Contracts.ChannelListItem","type":"Class"},{"name":"IChannelService","href":"core/EchoHub.Core.Contracts.IChannelService.html","topicHref":"core/EchoHub.Core.Contracts.IChannelService.html","topicUid":"EchoHub.Core.Contracts.IChannelService","type":"Interface"},{"name":"IChatBroadcaster","href":"core/EchoHub.Core.Contracts.IChatBroadcaster.html","topicHref":"core/EchoHub.Core.Contracts.IChatBroadcaster.html","topicUid":"EchoHub.Core.Contracts.IChatBroadcaster","type":"Interface"},{"name":"IChatService","href":"core/EchoHub.Core.Contracts.IChatService.html","topicHref":"core/EchoHub.Core.Contracts.IChatService.html","topicUid":"EchoHub.Core.Contracts.IChatService","type":"Interface"},{"name":"IEchoHubClient","href":"core/EchoHub.Core.Contracts.IEchoHubClient.html","topicHref":"core/EchoHub.Core.Contracts.IEchoHubClient.html","topicUid":"EchoHub.Core.Contracts.IEchoHubClient","type":"Interface"},{"name":"IMessageEncryptionService","href":"core/EchoHub.Core.Contracts.IMessageEncryptionService.html","topicHref":"core/EchoHub.Core.Contracts.IMessageEncryptionService.html","topicUid":"EchoHub.Core.Contracts.IMessageEncryptionService","type":"Interface"},{"name":"IUserService","href":"core/EchoHub.Core.Contracts.IUserService.html","topicHref":"core/EchoHub.Core.Contracts.IUserService.html","topicUid":"EchoHub.Core.Contracts.IUserService","type":"Interface"}]},{"name":"EchoHub.Core.DTOs","href":"core/EchoHub.Core.DTOs.html","topicHref":"core/EchoHub.Core.DTOs.html","topicUid":"EchoHub.Core.DTOs","type":"Namespace","items":[{"name":"ApiResponse","href":"core/EchoHub.Core.DTOs.ApiResponse.html","topicHref":"core/EchoHub.Core.DTOs.ApiResponse.html","topicUid":"EchoHub.Core.DTOs.ApiResponse","type":"Class"},{"name":"ApiResponse","href":"core/EchoHub.Core.DTOs.ApiResponse-1.html","topicHref":"core/EchoHub.Core.DTOs.ApiResponse-1.html","topicUid":"EchoHub.Core.DTOs.ApiResponse`1","type":"Class"},{"name":"AssignRoleRequest","href":"core/EchoHub.Core.DTOs.AssignRoleRequest.html","topicHref":"core/EchoHub.Core.DTOs.AssignRoleRequest.html","topicUid":"EchoHub.Core.DTOs.AssignRoleRequest","type":"Class"},{"name":"AttachmentDto","href":"core/EchoHub.Core.DTOs.AttachmentDto.html","topicHref":"core/EchoHub.Core.DTOs.AttachmentDto.html","topicUid":"EchoHub.Core.DTOs.AttachmentDto","type":"Class"},{"name":"AvatarUploadResponse","href":"core/EchoHub.Core.DTOs.AvatarUploadResponse.html","topicHref":"core/EchoHub.Core.DTOs.AvatarUploadResponse.html","topicUid":"EchoHub.Core.DTOs.AvatarUploadResponse","type":"Class"},{"name":"BanRequest","href":"core/EchoHub.Core.DTOs.BanRequest.html","topicHref":"core/EchoHub.Core.DTOs.BanRequest.html","topicUid":"EchoHub.Core.DTOs.BanRequest","type":"Class"},{"name":"ChannelCryptoDto","href":"core/EchoHub.Core.DTOs.ChannelCryptoDto.html","topicHref":"core/EchoHub.Core.DTOs.ChannelCryptoDto.html","topicUid":"EchoHub.Core.DTOs.ChannelCryptoDto","type":"Class"},{"name":"ChannelDto","href":"core/EchoHub.Core.DTOs.ChannelDto.html","topicHref":"core/EchoHub.Core.DTOs.ChannelDto.html","topicUid":"EchoHub.Core.DTOs.ChannelDto","type":"Class"},{"name":"ChannelError","href":"core/EchoHub.Core.DTOs.ChannelError.html","topicHref":"core/EchoHub.Core.DTOs.ChannelError.html","topicUid":"EchoHub.Core.DTOs.ChannelError","type":"Enum"},{"name":"ChannelOperationResult","href":"core/EchoHub.Core.DTOs.ChannelOperationResult.html","topicHref":"core/EchoHub.Core.DTOs.ChannelOperationResult.html","topicUid":"EchoHub.Core.DTOs.ChannelOperationResult","type":"Class"},{"name":"CreateChannelRequest","href":"core/EchoHub.Core.DTOs.CreateChannelRequest.html","topicHref":"core/EchoHub.Core.DTOs.CreateChannelRequest.html","topicUid":"EchoHub.Core.DTOs.CreateChannelRequest","type":"Class"},{"name":"EmbedDto","href":"core/EchoHub.Core.DTOs.EmbedDto.html","topicHref":"core/EchoHub.Core.DTOs.EmbedDto.html","topicUid":"EchoHub.Core.DTOs.EmbedDto","type":"Class"},{"name":"EncryptionKeyResponse","href":"core/EchoHub.Core.DTOs.EncryptionKeyResponse.html","topicHref":"core/EchoHub.Core.DTOs.EncryptionKeyResponse.html","topicUid":"EchoHub.Core.DTOs.EncryptionKeyResponse","type":"Class"},{"name":"ErrorResponse","href":"core/EchoHub.Core.DTOs.ErrorResponse.html","topicHref":"core/EchoHub.Core.DTOs.ErrorResponse.html","topicUid":"EchoHub.Core.DTOs.ErrorResponse","type":"Class"},{"name":"JoinChannelResult","href":"core/EchoHub.Core.DTOs.JoinChannelResult.html","topicHref":"core/EchoHub.Core.DTOs.JoinChannelResult.html","topicUid":"EchoHub.Core.DTOs.JoinChannelResult","type":"Class"},{"name":"KickRequest","href":"core/EchoHub.Core.DTOs.KickRequest.html","topicHref":"core/EchoHub.Core.DTOs.KickRequest.html","topicUid":"EchoHub.Core.DTOs.KickRequest","type":"Class"},{"name":"LoginRequest","href":"core/EchoHub.Core.DTOs.LoginRequest.html","topicHref":"core/EchoHub.Core.DTOs.LoginRequest.html","topicUid":"EchoHub.Core.DTOs.LoginRequest","type":"Class"},{"name":"LoginResponse","href":"core/EchoHub.Core.DTOs.LoginResponse.html","topicHref":"core/EchoHub.Core.DTOs.LoginResponse.html","topicUid":"EchoHub.Core.DTOs.LoginResponse","type":"Class"},{"name":"MessageDto","href":"core/EchoHub.Core.DTOs.MessageDto.html","topicHref":"core/EchoHub.Core.DTOs.MessageDto.html","topicUid":"EchoHub.Core.DTOs.MessageDto","type":"Class"},{"name":"MuteRequest","href":"core/EchoHub.Core.DTOs.MuteRequest.html","topicHref":"core/EchoHub.Core.DTOs.MuteRequest.html","topicUid":"EchoHub.Core.DTOs.MuteRequest","type":"Class"},{"name":"PaginatedResponse","href":"core/EchoHub.Core.DTOs.PaginatedResponse-1.html","topicHref":"core/EchoHub.Core.DTOs.PaginatedResponse-1.html","topicUid":"EchoHub.Core.DTOs.PaginatedResponse`1","type":"Class"},{"name":"RefreshRequest","href":"core/EchoHub.Core.DTOs.RefreshRequest.html","topicHref":"core/EchoHub.Core.DTOs.RefreshRequest.html","topicUid":"EchoHub.Core.DTOs.RefreshRequest","type":"Class"},{"name":"RegisterRequest","href":"core/EchoHub.Core.DTOs.RegisterRequest.html","topicHref":"core/EchoHub.Core.DTOs.RegisterRequest.html","topicUid":"EchoHub.Core.DTOs.RegisterRequest","type":"Class"},{"name":"RekeyChannelRequest","href":"core/EchoHub.Core.DTOs.RekeyChannelRequest.html","topicHref":"core/EchoHub.Core.DTOs.RekeyChannelRequest.html","topicUid":"EchoHub.Core.DTOs.RekeyChannelRequest","type":"Class"},{"name":"SendMessageRequest","href":"core/EchoHub.Core.DTOs.SendMessageRequest.html","topicHref":"core/EchoHub.Core.DTOs.SendMessageRequest.html","topicUid":"EchoHub.Core.DTOs.SendMessageRequest","type":"Class"},{"name":"SendUrlRequest","href":"core/EchoHub.Core.DTOs.SendUrlRequest.html","topicHref":"core/EchoHub.Core.DTOs.SendUrlRequest.html","topicUid":"EchoHub.Core.DTOs.SendUrlRequest","type":"Class"},{"name":"ServerStatusDto","href":"core/EchoHub.Core.DTOs.ServerStatusDto.html","topicHref":"core/EchoHub.Core.DTOs.ServerStatusDto.html","topicUid":"EchoHub.Core.DTOs.ServerStatusDto","type":"Class"},{"name":"UpdateProfileRequest","href":"core/EchoHub.Core.DTOs.UpdateProfileRequest.html","topicHref":"core/EchoHub.Core.DTOs.UpdateProfileRequest.html","topicUid":"EchoHub.Core.DTOs.UpdateProfileRequest","type":"Class"},{"name":"UpdateStatusRequest","href":"core/EchoHub.Core.DTOs.UpdateStatusRequest.html","topicHref":"core/EchoHub.Core.DTOs.UpdateStatusRequest.html","topicUid":"EchoHub.Core.DTOs.UpdateStatusRequest","type":"Class"},{"name":"UpdateTopicRequest","href":"core/EchoHub.Core.DTOs.UpdateTopicRequest.html","topicHref":"core/EchoHub.Core.DTOs.UpdateTopicRequest.html","topicUid":"EchoHub.Core.DTOs.UpdateTopicRequest","type":"Class"},{"name":"UserDto","href":"core/EchoHub.Core.DTOs.UserDto.html","topicHref":"core/EchoHub.Core.DTOs.UserDto.html","topicUid":"EchoHub.Core.DTOs.UserDto","type":"Class"},{"name":"UserError","href":"core/EchoHub.Core.DTOs.UserError.html","topicHref":"core/EchoHub.Core.DTOs.UserError.html","topicUid":"EchoHub.Core.DTOs.UserError","type":"Enum"},{"name":"UserOperationResult","href":"core/EchoHub.Core.DTOs.UserOperationResult.html","topicHref":"core/EchoHub.Core.DTOs.UserOperationResult.html","topicUid":"EchoHub.Core.DTOs.UserOperationResult","type":"Class"},{"name":"UserPresenceDto","href":"core/EchoHub.Core.DTOs.UserPresenceDto.html","topicHref":"core/EchoHub.Core.DTOs.UserPresenceDto.html","topicUid":"EchoHub.Core.DTOs.UserPresenceDto","type":"Class"},{"name":"UserProfileDto","href":"core/EchoHub.Core.DTOs.UserProfileDto.html","topicHref":"core/EchoHub.Core.DTOs.UserProfileDto.html","topicUid":"EchoHub.Core.DTOs.UserProfileDto","type":"Class"}]},{"name":"EchoHub.Core.Models","href":"core/EchoHub.Core.Models.html","topicHref":"core/EchoHub.Core.Models.html","topicUid":"EchoHub.Core.Models","type":"Namespace","items":[{"name":"Attachment","href":"core/EchoHub.Core.Models.Attachment.html","topicHref":"core/EchoHub.Core.Models.Attachment.html","topicUid":"EchoHub.Core.Models.Attachment","type":"Class"},{"name":"AttachmentKind","href":"core/EchoHub.Core.Models.AttachmentKind.html","topicHref":"core/EchoHub.Core.Models.AttachmentKind.html","topicUid":"EchoHub.Core.Models.AttachmentKind","type":"Enum"},{"name":"Channel","href":"core/EchoHub.Core.Models.Channel.html","topicHref":"core/EchoHub.Core.Models.Channel.html","topicUid":"EchoHub.Core.Models.Channel","type":"Class"},{"name":"ChannelMembership","href":"core/EchoHub.Core.Models.ChannelMembership.html","topicHref":"core/EchoHub.Core.Models.ChannelMembership.html","topicUid":"EchoHub.Core.Models.ChannelMembership","type":"Class"},{"name":"Message","href":"core/EchoHub.Core.Models.Message.html","topicHref":"core/EchoHub.Core.Models.Message.html","topicUid":"EchoHub.Core.Models.Message","type":"Class"},{"name":"MessageType","href":"core/EchoHub.Core.Models.MessageType.html","topicHref":"core/EchoHub.Core.Models.MessageType.html","topicUid":"EchoHub.Core.Models.MessageType","type":"Enum"},{"name":"RefreshToken","href":"core/EchoHub.Core.Models.RefreshToken.html","topicHref":"core/EchoHub.Core.Models.RefreshToken.html","topicUid":"EchoHub.Core.Models.RefreshToken","type":"Class"},{"name":"ServerRole","href":"core/EchoHub.Core.Models.ServerRole.html","topicHref":"core/EchoHub.Core.Models.ServerRole.html","topicUid":"EchoHub.Core.Models.ServerRole","type":"Enum"},{"name":"User","href":"core/EchoHub.Core.Models.User.html","topicHref":"core/EchoHub.Core.Models.User.html","topicUid":"EchoHub.Core.Models.User","type":"Class"},{"name":"UserStatus","href":"core/EchoHub.Core.Models.UserStatus.html","topicHref":"core/EchoHub.Core.Models.UserStatus.html","topicUid":"EchoHub.Core.Models.UserStatus","type":"Enum"}]},{"name":"EchoHub.Core.Security","href":"core/EchoHub.Core.Security.html","topicHref":"core/EchoHub.Core.Security.html","topicUid":"EchoHub.Core.Security","type":"Namespace","items":[{"name":"RoomCrypto","href":"core/EchoHub.Core.Security.RoomCrypto.html","topicHref":"core/EchoHub.Core.Security.RoomCrypto.html","topicUid":"EchoHub.Core.Security.RoomCrypto","type":"Class"},{"name":"RoomCrypto.DerivedKeys","href":"core/EchoHub.Core.Security.RoomCrypto.DerivedKeys.html","topicHref":"core/EchoHub.Core.Security.RoomCrypto.DerivedKeys.html","topicUid":"EchoHub.Core.Security.RoomCrypto.DerivedKeys","type":"Class"}]},{"name":"EchoHub.Core.Services","href":"core/EchoHub.Core.Services.html","topicHref":"core/EchoHub.Core.Services.html","topicUid":"EchoHub.Core.Services","type":"Namespace","items":[{"name":"FileValidationHelper","href":"core/EchoHub.Core.Services.FileValidationHelper.html","topicHref":"core/EchoHub.Core.Services.FileValidationHelper.html","topicUid":"EchoHub.Core.Services.FileValidationHelper","type":"Class"},{"name":"ImageToAsciiService","href":"core/EchoHub.Core.Services.ImageToAsciiService.html","topicHref":"core/EchoHub.Core.Services.ImageToAsciiService.html","topicUid":"EchoHub.Core.Services.ImageToAsciiService","type":"Class"}]}]},{"name":"Articles","includedFrom":"~/api/core-articles/toc.yml","items":[{"name":"Overview","href":"core-articles/index.html","topicHref":"core-articles/index.html"}]}]},{"name":"Server","items":[{"name":"API Reference","includedFrom":"~/_api_meta/server/toc.yml","items":[{"name":"EchoHub.Server.Auth","href":"server/EchoHub.Server.Auth.html","topicHref":"server/EchoHub.Server.Auth.html","topicUid":"EchoHub.Server.Auth","type":"Namespace","items":[{"name":"JwtTokenService","href":"server/EchoHub.Server.Auth.JwtTokenService.html","topicHref":"server/EchoHub.Server.Auth.JwtTokenService.html","topicUid":"EchoHub.Server.Auth.JwtTokenService","type":"Class"}]},{"name":"EchoHub.Server.Controllers","href":"server/EchoHub.Server.Controllers.html","topicHref":"server/EchoHub.Server.Controllers.html","topicUid":"EchoHub.Server.Controllers","type":"Namespace","items":[{"name":"AuthController","href":"server/EchoHub.Server.Controllers.AuthController.html","topicHref":"server/EchoHub.Server.Controllers.AuthController.html","topicUid":"EchoHub.Server.Controllers.AuthController","type":"Class"},{"name":"ChannelsController","href":"server/EchoHub.Server.Controllers.ChannelsController.html","topicHref":"server/EchoHub.Server.Controllers.ChannelsController.html","topicUid":"EchoHub.Server.Controllers.ChannelsController","type":"Class"},{"name":"FilesController","href":"server/EchoHub.Server.Controllers.FilesController.html","topicHref":"server/EchoHub.Server.Controllers.FilesController.html","topicUid":"EchoHub.Server.Controllers.FilesController","type":"Class"},{"name":"ModerationController","href":"server/EchoHub.Server.Controllers.ModerationController.html","topicHref":"server/EchoHub.Server.Controllers.ModerationController.html","topicUid":"EchoHub.Server.Controllers.ModerationController","type":"Class"},{"name":"ServerController","href":"server/EchoHub.Server.Controllers.ServerController.html","topicHref":"server/EchoHub.Server.Controllers.ServerController.html","topicUid":"EchoHub.Server.Controllers.ServerController","type":"Class"},{"name":"UsersController","href":"server/EchoHub.Server.Controllers.UsersController.html","topicHref":"server/EchoHub.Server.Controllers.UsersController.html","topicUid":"EchoHub.Server.Controllers.UsersController","type":"Class"}]},{"name":"EchoHub.Server.Data","href":"server/EchoHub.Server.Data.html","topicHref":"server/EchoHub.Server.Data.html","topicUid":"EchoHub.Server.Data","type":"Namespace","items":[{"name":"EchoHubDbContext","href":"server/EchoHub.Server.Data.EchoHubDbContext.html","topicHref":"server/EchoHub.Server.Data.EchoHubDbContext.html","topicUid":"EchoHub.Server.Data.EchoHubDbContext","type":"Class"}]},{"name":"EchoHub.Server.Data.Migrations","href":"server/EchoHub.Server.Data.Migrations.html","topicHref":"server/EchoHub.Server.Data.Migrations.html","topicUid":"EchoHub.Server.Data.Migrations","type":"Namespace","items":[{"name":"AddAttachmentFileSize","href":"server/EchoHub.Server.Data.Migrations.AddAttachmentFileSize.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddAttachmentFileSize.html","topicUid":"EchoHub.Server.Data.Migrations.AddAttachmentFileSize","type":"Class"},{"name":"AddChannelEncryptionEnvelope","href":"server/EchoHub.Server.Data.Migrations.AddChannelEncryptionEnvelope.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddChannelEncryptionEnvelope.html","topicUid":"EchoHub.Server.Data.Migrations.AddChannelEncryptionEnvelope","type":"Class"},{"name":"AddChannelIsPublic","href":"server/EchoHub.Server.Data.Migrations.AddChannelIsPublic.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddChannelIsPublic.html","topicUid":"EchoHub.Server.Data.Migrations.AddChannelIsPublic","type":"Class"},{"name":"AddChannelMembership","href":"server/EchoHub.Server.Data.Migrations.AddChannelMembership.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddChannelMembership.html","topicUid":"EchoHub.Server.Data.Migrations.AddChannelMembership","type":"Class"},{"name":"AddChannelPasswordHash","href":"server/EchoHub.Server.Data.Migrations.AddChannelPasswordHash.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddChannelPasswordHash.html","topicUid":"EchoHub.Server.Data.Migrations.AddChannelPasswordHash","type":"Class"},{"name":"AddEncryptionSupport","href":"server/EchoHub.Server.Data.Migrations.AddEncryptionSupport.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddEncryptionSupport.html","topicUid":"EchoHub.Server.Data.Migrations.AddEncryptionSupport","type":"Class"},{"name":"AddMessageAttachments","href":"server/EchoHub.Server.Data.Migrations.AddMessageAttachments.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddMessageAttachments.html","topicUid":"EchoHub.Server.Data.Migrations.AddMessageAttachments","type":"Class"},{"name":"AddMessageEmbed","href":"server/EchoHub.Server.Data.Migrations.AddMessageEmbed.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddMessageEmbed.html","topicUid":"EchoHub.Server.Data.Migrations.AddMessageEmbed","type":"Class"},{"name":"AddModerationRoles","href":"server/EchoHub.Server.Data.Migrations.AddModerationRoles.html","topicHref":"server/EchoHub.Server.Data.Migrations.AddModerationRoles.html","topicUid":"EchoHub.Server.Data.Migrations.AddModerationRoles","type":"Class"},{"name":"InitialCreate","href":"server/EchoHub.Server.Data.Migrations.InitialCreate.html","topicHref":"server/EchoHub.Server.Data.Migrations.InitialCreate.html","topicUid":"EchoHub.Server.Data.Migrations.InitialCreate","type":"Class"}]},{"name":"EchoHub.Server.Hubs","href":"server/EchoHub.Server.Hubs.html","topicHref":"server/EchoHub.Server.Hubs.html","topicUid":"EchoHub.Server.Hubs","type":"Namespace","items":[{"name":"ChatHub","href":"server/EchoHub.Server.Hubs.ChatHub.html","topicHref":"server/EchoHub.Server.Hubs.ChatHub.html","topicUid":"EchoHub.Server.Hubs.ChatHub","type":"Class"}]},{"name":"EchoHub.Server.Services","href":"server/EchoHub.Server.Services.html","topicHref":"server/EchoHub.Server.Services.html","topicUid":"EchoHub.Server.Services","type":"Namespace","items":[{"name":"ChannelService","href":"server/EchoHub.Server.Services.ChannelService.html","topicHref":"server/EchoHub.Server.Services.ChannelService.html","topicUid":"EchoHub.Server.Services.ChannelService","type":"Class"},{"name":"ChatService","href":"server/EchoHub.Server.Services.ChatService.html","topicHref":"server/EchoHub.Server.Services.ChatService.html","topicUid":"EchoHub.Server.Services.ChatService","type":"Class"},{"name":"DirectoryClaimStore","href":"server/EchoHub.Server.Services.DirectoryClaimStore.html","topicHref":"server/EchoHub.Server.Services.DirectoryClaimStore.html","topicUid":"EchoHub.Server.Services.DirectoryClaimStore","type":"Class"},{"name":"FileCleanupService","href":"server/EchoHub.Server.Services.FileCleanupService.html","topicHref":"server/EchoHub.Server.Services.FileCleanupService.html","topicUid":"EchoHub.Server.Services.FileCleanupService","type":"Class"},{"name":"FileStorageService","href":"server/EchoHub.Server.Services.FileStorageService.html","topicHref":"server/EchoHub.Server.Services.FileStorageService.html","topicUid":"EchoHub.Server.Services.FileStorageService","type":"Class"},{"name":"LinkEmbedService","href":"server/EchoHub.Server.Services.LinkEmbedService.html","topicHref":"server/EchoHub.Server.Services.LinkEmbedService.html","topicUid":"EchoHub.Server.Services.LinkEmbedService","type":"Class"},{"name":"MessageEncryptionService","href":"server/EchoHub.Server.Services.MessageEncryptionService.html","topicHref":"server/EchoHub.Server.Services.MessageEncryptionService.html","topicUid":"EchoHub.Server.Services.MessageEncryptionService","type":"Class"},{"name":"MuteExpirationService","href":"server/EchoHub.Server.Services.MuteExpirationService.html","topicHref":"server/EchoHub.Server.Services.MuteExpirationService.html","topicUid":"EchoHub.Server.Services.MuteExpirationService","type":"Class"},{"name":"PresenceTracker","href":"server/EchoHub.Server.Services.PresenceTracker.html","topicHref":"server/EchoHub.Server.Services.PresenceTracker.html","topicUid":"EchoHub.Server.Services.PresenceTracker","type":"Class"},{"name":"RegistrationStatus","href":"server/EchoHub.Server.Services.RegistrationStatus.html","topicHref":"server/EchoHub.Server.Services.RegistrationStatus.html","topicUid":"EchoHub.Server.Services.RegistrationStatus","type":"Class"},{"name":"ServerDirectoryService","href":"server/EchoHub.Server.Services.ServerDirectoryService.html","topicHref":"server/EchoHub.Server.Services.ServerDirectoryService.html","topicUid":"EchoHub.Server.Services.ServerDirectoryService","type":"Class"},{"name":"SignalRBroadcaster","href":"server/EchoHub.Server.Services.SignalRBroadcaster.html","topicHref":"server/EchoHub.Server.Services.SignalRBroadcaster.html","topicUid":"EchoHub.Server.Services.SignalRBroadcaster","type":"Class"},{"name":"UserService","href":"server/EchoHub.Server.Services.UserService.html","topicHref":"server/EchoHub.Server.Services.UserService.html","topicUid":"EchoHub.Server.Services.UserService","type":"Class"}]},{"name":"EchoHub.Server.Setup","href":"server/EchoHub.Server.Setup.html","topicHref":"server/EchoHub.Server.Setup.html","topicUid":"EchoHub.Server.Setup","type":"Namespace","items":[{"name":"DataMigrationService","href":"server/EchoHub.Server.Setup.DataMigrationService.html","topicHref":"server/EchoHub.Server.Setup.DataMigrationService.html","topicUid":"EchoHub.Server.Setup.DataMigrationService","type":"Class"},{"name":"DatabaseSetup","href":"server/EchoHub.Server.Setup.DatabaseSetup.html","topicHref":"server/EchoHub.Server.Setup.DatabaseSetup.html","topicUid":"EchoHub.Server.Setup.DatabaseSetup","type":"Class"},{"name":"FirstRunSetup","href":"server/EchoHub.Server.Setup.FirstRunSetup.html","topicHref":"server/EchoHub.Server.Setup.FirstRunSetup.html","topicUid":"EchoHub.Server.Setup.FirstRunSetup","type":"Class"}]}]},{"name":"Articles","includedFrom":"~/api/server-articles/toc.yml","items":[{"name":"Overview","href":"server-articles/index.html","topicHref":"server-articles/index.html"}]}]},{"name":"Server.Irc","items":[{"name":"API Reference","includedFrom":"~/_api_meta/server-irc/toc.yml","items":[{"name":"EchoHub.Server.Irc","href":"server-irc/EchoHub.Server.Irc.html","topicHref":"server-irc/EchoHub.Server.Irc.html","topicUid":"EchoHub.Server.Irc","type":"Namespace","items":[{"name":"IrcBroadcaster","href":"server-irc/EchoHub.Server.Irc.IrcBroadcaster.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcBroadcaster.html","topicUid":"EchoHub.Server.Irc.IrcBroadcaster","type":"Class"},{"name":"IrcClientConnection","href":"server-irc/EchoHub.Server.Irc.IrcClientConnection.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcClientConnection.html","topicUid":"EchoHub.Server.Irc.IrcClientConnection","type":"Class"},{"name":"IrcCommandHandler","href":"server-irc/EchoHub.Server.Irc.IrcCommandHandler.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcCommandHandler.html","topicUid":"EchoHub.Server.Irc.IrcCommandHandler","type":"Class"},{"name":"IrcGatewayService","href":"server-irc/EchoHub.Server.Irc.IrcGatewayService.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcGatewayService.html","topicUid":"EchoHub.Server.Irc.IrcGatewayService","type":"Class"},{"name":"IrcMessage","href":"server-irc/EchoHub.Server.Irc.IrcMessage.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcMessage.html","topicUid":"EchoHub.Server.Irc.IrcMessage","type":"Class"},{"name":"IrcMessageFormatter","href":"server-irc/EchoHub.Server.Irc.IrcMessageFormatter.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcMessageFormatter.html","topicUid":"EchoHub.Server.Irc.IrcMessageFormatter","type":"Class"},{"name":"IrcNumericReply","href":"server-irc/EchoHub.Server.Irc.IrcNumericReply.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcNumericReply.html","topicUid":"EchoHub.Server.Irc.IrcNumericReply","type":"Class"},{"name":"IrcOptions","href":"server-irc/EchoHub.Server.Irc.IrcOptions.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcOptions.html","topicUid":"EchoHub.Server.Irc.IrcOptions","type":"Class"},{"name":"IrcServiceExtensions","href":"server-irc/EchoHub.Server.Irc.IrcServiceExtensions.html","topicHref":"server-irc/EchoHub.Server.Irc.IrcServiceExtensions.html","topicUid":"EchoHub.Server.Irc.IrcServiceExtensions","type":"Class"}]}]}]}]}
diff --git a/articles/architecture.html b/articles/architecture.html
index 503ee2a..58353d4 100644
--- a/articles/architecture.html
+++ b/articles/architecture.html
@@ -127,7 +127,7 @@ TUI Client ──► WebSocket ──► ChatHub ─────┘
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)
+Themes : 14 built-in color themes (including transparent dark/light themes with true terminal transparency)
Config : Client configuration management with session persistence ("Remember Me" refresh tokens)
Communication
diff --git a/changelog/index.html b/changelog/index.html
index 23a90ca..ca8ee1d 100644
--- a/changelog/index.html
+++ b/changelog/index.html
@@ -90,6 +90,7 @@
Release history for EchoHub.
Releases
+v0.2.12 - End-to-End Encrypted Channels, IRC Channel Keys, Image Save & Ctrl+W Crash Fix
v0.2.11 - EchoHubSpace Auth, Live Directory Updates & Server Browser Metadata
v0.2.10 - Command Palette, Infinite History Scroll & Auto-Updater Fixes
v0.2.9 - Install Script & Chocolatey Fixes
diff --git a/changelog/toc.html b/changelog/toc.html
index 0ad1431..5522b12 100644
--- a/changelog/toc.html
+++ b/changelog/toc.html
@@ -15,6 +15,9 @@
Overview
+
+ v0.2.12
+
v0.2.11
diff --git a/changelog/toc.json b/changelog/toc.json
index 7d2ec0a..26ccc79 100644
--- a/changelog/toc.json
+++ b/changelog/toc.json
@@ -1,2 +1,2 @@
-{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"v0.2.11","href":"v0.2.11.html","topicHref":"v0.2.11.html"},{"name":"v0.2.10","href":"v0.2.10.html","topicHref":"v0.2.10.html"},{"name":"v0.2.9","href":"v0.2.9.html","topicHref":"v0.2.9.html"},{"name":"v0.2.8","href":"v0.2.8.html","topicHref":"v0.2.8.html"},{"name":"v0.2.7","href":"v0.2.7.html","topicHref":"v0.2.7.html"},{"name":"v0.2.6","href":"v0.2.6.html","topicHref":"v0.2.6.html"},{"name":"v0.2.5","href":"v0.2.5.html","topicHref":"v0.2.5.html"},{"name":"v0.2.4","href":"v0.2.4.html","topicHref":"v0.2.4.html"},{"name":"v0.2.3","href":"v0.2.3.html","topicHref":"v0.2.3.html"},{"name":"v0.2.2","href":"v0.2.2.html","topicHref":"v0.2.2.html"},{"name":"v0.2.1","href":"v0.2.1.html","topicHref":"v0.2.1.html"},{"name":"v0.2.0","href":"v0.2.0.html","topicHref":"v0.2.0.html"},{"name":"v0.1.1","href":"v0.1.1.html","topicHref":"v0.1.1.html"},{"name":"v0.1.0","href":"v0.1.0.html","topicHref":"v0.1.0.html"}]}
+{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"v0.2.12","href":"v0.2.12.html","topicHref":"v0.2.12.html"},{"name":"v0.2.11","href":"v0.2.11.html","topicHref":"v0.2.11.html"},{"name":"v0.2.10","href":"v0.2.10.html","topicHref":"v0.2.10.html"},{"name":"v0.2.9","href":"v0.2.9.html","topicHref":"v0.2.9.html"},{"name":"v0.2.8","href":"v0.2.8.html","topicHref":"v0.2.8.html"},{"name":"v0.2.7","href":"v0.2.7.html","topicHref":"v0.2.7.html"},{"name":"v0.2.6","href":"v0.2.6.html","topicHref":"v0.2.6.html"},{"name":"v0.2.5","href":"v0.2.5.html","topicHref":"v0.2.5.html"},{"name":"v0.2.4","href":"v0.2.4.html","topicHref":"v0.2.4.html"},{"name":"v0.2.3","href":"v0.2.3.html","topicHref":"v0.2.3.html"},{"name":"v0.2.2","href":"v0.2.2.html","topicHref":"v0.2.2.html"},{"name":"v0.2.1","href":"v0.2.1.html","topicHref":"v0.2.1.html"},{"name":"v0.2.0","href":"v0.2.0.html","topicHref":"v0.2.0.html"},{"name":"v0.1.1","href":"v0.1.1.html","topicHref":"v0.1.1.html"},{"name":"v0.1.0","href":"v0.1.0.html","topicHref":"v0.1.0.html"}]}
diff --git a/changelog/v0.2.12.html b/changelog/v0.2.12.html
new file mode 100644
index 0000000..1f575e1
--- /dev/null
+++ b/changelog/v0.2.12.html
@@ -0,0 +1,169 @@
+
+
+
+
+ v0.2.12 | EchoHub Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+v0.2.12
+
+Private channels are now genuinely private: password-protected channels are end-to-end encrypted, so the server (and its operators) can gate joins and measure storage but cannot read message or file contents. The IRC gateway grows real MODE/TOPIC support and channel keys, and the client gets image "save original", a transparent-light theme, drag-and-drop file sending, Ctrl+V paste, and a fix for the intermittent Ctrl+W crash.
+New Features
+
+End-to-end encrypted channels — creating a channel with a password now provisions a zero-knowledge room:
+
+The passphrase never leaves the client. It derives (PBKDF2-SHA256, 210k iterations) two keys: an auth key sent to the server as the join credential, and a key-encryption key that never leaves the machine.
+A random room content key encrypts every message and file with AES-256-GCM. The server only ever stores the room key wrapped under the passphrase, so it can gate joins and report a channel's message count, storage size, and attachments — but cannot decrypt any of it. Even the server owner cannot read a private room's contents.
+Members' clients cache the derived room key locally (in the per-server config, like saved sessions) so the passphrase isn't retyped every launch; joining on a new device prompts for it once.
+Change the passphrase with /passwd <old> <new> (channel creator only). The room key is re-wrapped, not rotated, so existing history stays readable and members who join later with the new passphrase can still read older messages.
+Files and images are encrypted client-side before upload; for images the ASCII-art preview is rendered on the client and stored room-encrypted too. Sending images by URL is disabled in encrypted channels (the server can't fetch-and-render without the key).
+End-to-end encrypted channels cannot be joined over the IRC gateway (that would require the server to hold the room key) — IRC JOIN returns 475 directing users to the EchoHub client.
+
+
+Password-protected channels — set an optional password when creating a channel (masked field in the Create Channel dialog, password on POST /api/channels). Passwords are BCrypt-hashed server-side; the join gate applies on first join only (existing members and the creator are unaffected). Protected channels show a * marker in the channel list and +k in the status bar
+Save original images — image messages now show a clickable "[↓ save original]" line under the ASCII-art preview that downloads the full-resolution original to your Downloads folder (decrypting locally in encrypted channels)
+Messages with attachments (Discord-style) — a message is now text plus a list of attachments instead of being either text or a single file. One message can carry a caption and several files (images, audio, docs) together:
+
+Compose with a staging tray : /send <file> or dropping files onto the terminal stages them (shown on the input bar); the next Enter sends your typed caption and all staged files as one message. /clear drops staged files. /send <URL> still posts an image immediately.
+Each image attachment renders its own ASCII preview with its own "save original" action; audio/file attachments each get their own play/download line.
+In encrypted channels every attachment is encrypted individually (blob + ASCII preview), and the caption is room-encrypted — the server still stores only ciphertext and can report count/size but not contents.
+Up to 10 attachments per message.
+
+
+Right-click message menu — right-click any message for a context menu: save/download/play its attachment, mention the sender, view their profile, copy the text, copy the message ID (for linking or command arguments), or delete the message. (Keyboard: F6 focuses the message list for arrow-key selection + Delete.) The selected message is now highlighted while the list is focused.
+Message deletion — press Delete on a selected message to remove it. You can always delete your own messages; moderators and above can delete others' messages, but only from users below their own role (a mod can't delete an admin's or owner's message). Deleting a message also removes its attachment blobs from server storage.
+Customizable download folder — /downloadpath opens your OS-native folder picker (Windows Explorer / macOS Finder / Linux GTK or KDE) to choose where downloaded attachments and saved images go; /downloadpath <path> sets it directly (the fallback when no native picker is available). Downloaded files now land in that folder (with automatic (n) de-duplication) instead of a temp directory.
+/join <channel> [password] — join protected channels inline, or let the client prompt: joining a protected channel without a password opens a masked prompt that re-prompts on a wrong password
+IRC channel keys — JOIN #room <key> works against room passwords (RFC 1459 comma-paired key lists supported); keyless or wrong-key joins get 475 ERR_BADCHANNELKEY
+IRC MODE implemented — MODE #chan reports +k/+, MODE #chan +k <key> sets and -k clears the room password (channel creator or admin only), ban-list probes get a clean empty reply, and CHANMODES is advertised in ISUPPORT
+IRC TOPIC set support — the channel creator can change the topic from IRC; the change broadcasts to connected TUI clients (previously topic changes were rejected with a stub error)
+Attach a file by drag & drop or by pasting — drop a file onto the terminal, or copy a file in your file manager and press Ctrl+V , to stage it as an attachment (the next Enter sends it with your caption). Multiple files at once are supported. Ctrl+V still pastes text when the clipboard holds text; Ctrl+Y is a paste alias. On Windows the copied-file paste reads the clipboard's file list directly (Windows Terminal never pastes copied files as text), with xclip/wl-paste used on Linux
+Pick ASCII-art size for attached images — /size opens a Small/Medium/Large picker (40×40 / 80×80 / 120×120) with descriptions, /size <s|m|l> sets it directly, and /send <file> -l sets it for that message. The choice is a saved preference and applies to copy-paste/drag-drop images (which have no per-file flag); the current size is shown in the staging tray
+New TransparentLight theme — dark characters on a transparent background, for light terminal color schemes (/theme transparentlight)
+Timestamps in messages are now aware of the current culture and display the short time pattern for today's messages and the short date+time pattern for older messages.
+
+Bug Fixes
+
+Transparent themes no longer draw an opaque box behind the message input. The input TextView renders with the Editable visual role, which Terminal.Gui derives as an opaque color when a theme leaves it unset; the themes now pin Editable/ReadOnly to their base colors so the input matches its (transparent) background.
+Attachments whose files have been pruned (retention cleanup deletes blobs older than Storage:RetentionDays but left the message rows) no longer render a dead download/preview. When channel history loads, the server checks which attachment blobs still exist: missing ones are dropped from the message, and an attachment-only message whose files are all gone is removed from the database.
+Fixed intermittent crash on Ctrl+W — Terminal.Gui binds Ctrl+W to clipboard-cut, and Windows clipboard contention (another app holding the clipboard) threw an unhandled Win32Exception that took the app down. Ctrl+W now deletes the previous word (readline behavior, no clipboard), and all clipboard shortcuts (Ctrl+X/C/V/Y) are guarded so transient clipboard failures log a warning instead of crashing
+Fixed emoji shortcode replacement permanently disabling itself if a cursor update threw mid-replacement
+IRC LIST no longer leaks private channels; protected channels are marked [+k]
+
+API Changes
+
+ChannelDto gains isProtected and isEncrypted; CreateChannelRequest gains optional password, encryptionSalt, and wrappedRoomKey; SignalR JoinChannel takes an optional second password argument and JoinChannelResult gains passwordRequired, encryptionSalt, and wrappedRoomKey (older clients must update to join over SignalR)
+New endpoints: GET /api/channels/{channel}/crypto (public crypto metadata — salt only, never the wrapped key) and POST /api/channels/{channel}/rekey (creator-only passphrase change)
+The upload endpoint accepts type and content form fields for encrypted channels, where the client supplies the declared message type and room-encrypted content
+ImageToAsciiService and FileValidationHelper moved from EchoHub.Server to EchoHub.Core so the client can render ASCII art and detect file types for encrypted uploads
+Message shape change : MessageDto drops Type/AttachmentUrl/AttachmentFileName/AttachmentFileSize and gains Attachments (a list of AttachmentDto { Kind, Url, FileName, FileSize, AsciiPreview }, null/empty for plain text). New Attachment entity + table with a cascade FK to Message
+New endpoint POST /api/channels/{channel}/messages (multipart: content + N files, plus kind/preview per file for encrypted channels) replaces the single-file upload endpoint; DELETE /api/moderation/messages/{id} now enforces the own-or-higher-role rule
+New EF migrations AddChannelPasswordHash, AddChannelEncryptionEnvelope, and AddMessageAttachments (applied automatically on server start); a one-time startup data migration folds legacy single-attachment messages into the new model
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/index.json b/index.json
index deb0b65..eb3a808 100644
--- a/index.json
+++ b/index.json
@@ -12,7 +12,7 @@
"api/client/EchoHub.Client.Commands.CommandHandler.html": {
"href": "api/client/EchoHub.Client.Commands.CommandHandler.html",
"title": "Class CommandHandler | EchoHub Documentation",
- "summary": "Class CommandHandler Namespace EchoHub.Client.Commands Assembly EchoHub.Client.dll public class CommandHandler Inheritance object CommandHandler Inherited Members object.GetType() object.MemberwiseClone() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors CommandHandler() public CommandHandler() Methods HandleAsync(string) public Task HandleAsync(string input) Parameters input string Returns Task IsCommand(string) public bool IsCommand(string input) Parameters input string Returns bool Events OnAssignRole public event Func? OnAssignRole Event Type Func OnBanUser public event Func? OnBanUser Event Type Func OnHelp public event Func? OnHelp Event Type Func OnJoinChannel public event Func? OnJoinChannel Event Type Func OnKickUser public event Func? OnKickUser Event Type Func OnLeaveChannel public event Func? OnLeaveChannel Event Type Func OnListUsers public event Func? OnListUsers Event Type Func OnMuteUser public event Func? OnMuteUser Event Type Func OnNukeChannel public event Func? OnNukeChannel Event Type Func OnOpenProfile public event Func? OnOpenProfile Event Type Func OnOpenServers public event Func? OnOpenServers Event Type Func OnQuit public event Func? OnQuit Event Type Func OnSendFile public event Func? OnSendFile Event Type Func OnSetAvatar public event Func? OnSetAvatar Event Type Func OnSetColor public event Func? OnSetColor Event Type Func OnSetNick public event Func? OnSetNick Event Type Func OnSetStatus public event Func? OnSetStatus Event Type Func OnSetTheme public event Func? OnSetTheme Event Type Func OnSetTopic public event Func? OnSetTopic Event Type Func OnTestSound public event Func? OnTestSound Event Type Func OnUnbanUser public event Func? OnUnbanUser Event Type Func OnUnmuteUser public event Func? OnUnmuteUser Event Type Func"
+ "summary": "Class CommandHandler Namespace EchoHub.Client.Commands Assembly EchoHub.Client.dll public class CommandHandler Inheritance object CommandHandler Inherited Members object.GetType() object.MemberwiseClone() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors CommandHandler() public CommandHandler() Methods HandleAsync(string) public Task HandleAsync(string input) Parameters input string Returns Task IsCommand(string) public bool IsCommand(string input) Parameters input string Returns bool Events OnAssignRole public event Func? OnAssignRole Event Type Func OnBanUser public event Func? OnBanUser Event Type Func OnChangeRoomPassword public event Func? OnChangeRoomPassword Event Type Func OnClearAttachments public event Func? OnClearAttachments Event Type Func OnHelp public event Func? OnHelp Event Type Func OnJoinChannel public event Func? OnJoinChannel Event Type Func OnKickUser public event Func? OnKickUser Event Type Func OnLeaveChannel public event Func? OnLeaveChannel Event Type Func OnListUsers public event Func? OnListUsers Event Type Func OnMuteUser public event Func? OnMuteUser Event Type Func OnNukeChannel public event Func? OnNukeChannel Event Type Func OnOpenProfile public event Func? OnOpenProfile Event Type Func OnOpenServers public event Func? OnOpenServers Event Type Func OnQuit public event Func? OnQuit Event Type Func OnSendFile public event Func? OnSendFile Event Type Func OnSetAsciiSize public event Func? OnSetAsciiSize Event Type Func OnSetAvatar public event Func? OnSetAvatar Event Type Func OnSetColor public event Func? OnSetColor Event Type Func OnSetDownloadPath public event Func? OnSetDownloadPath Event Type Func OnSetNick public event Func? OnSetNick Event Type Func OnSetStatus public event Func? OnSetStatus Event Type Func OnSetTheme public event Func? OnSetTheme Event Type Func OnSetTopic public event Func? OnSetTopic Event Type Func OnTestSound public event Func? OnTestSound Event Type Func OnUnbanUser public event Func? OnUnbanUser Event Type Func OnUnmuteUser public event Func? OnUnmuteUser Event Type Func"
},
"api/client/EchoHub.Client.Commands.CommandResult.html": {
"href": "api/client/EchoHub.Client.Commands.CommandResult.html",
@@ -32,7 +32,7 @@
"api/client/EchoHub.Client.Config.ClientConfig.html": {
"href": "api/client/EchoHub.Client.Config.ClientConfig.html",
"title": "Class ClientConfig | EchoHub Documentation",
- "summary": "Class ClientConfig Namespace EchoHub.Client.Config Assembly EchoHub.Client.dll public class ClientConfig Inheritance object ClientConfig Inherited Members object.GetType() object.MemberwiseClone() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors ClientConfig() public ClientConfig() Properties ActiveTheme public string ActiveTheme { get; set; } Property Value string DefaultPreset public AccountPreset DefaultPreset { get; set; } Property Value AccountPreset Notifications public NotificationConfig Notifications { get; set; } Property Value NotificationConfig SavedServers public List SavedServers { get; set; } Property Value List"
+ "summary": "Class ClientConfig Namespace EchoHub.Client.Config Assembly EchoHub.Client.dll public class ClientConfig Inheritance object ClientConfig Inherited Members object.GetType() object.MemberwiseClone() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors ClientConfig() public ClientConfig() Properties ActiveTheme public string ActiveTheme { get; set; } Property Value string DefaultAsciiSize ASCII-art rendering size for images you attach: \"s\" (40×40), \"m\" (80×80), or \"l\" (120×120). Applies to copy-paste/drag-drop attachments, which have no per-file size flag. public string DefaultAsciiSize { get; set; } Property Value string DefaultPreset public AccountPreset DefaultPreset { get; set; } Property Value AccountPreset DownloadPath Folder where downloaded attachments and saved images are written. When null, the OS Downloads folder is used. Set via the native folder picker or /downloadpath. public string? DownloadPath { get; set; } Property Value string Notifications public NotificationConfig Notifications { get; set; } Property Value NotificationConfig SavedServers public List SavedServers { get; set; } Property Value List"
},
"api/client/EchoHub.Client.Config.ConfigManager.html": {
"href": "api/client/EchoHub.Client.Config.ConfigManager.html",
@@ -47,7 +47,7 @@
"api/client/EchoHub.Client.Config.SavedServer.html": {
"href": "api/client/EchoHub.Client.Config.SavedServer.html",
"title": "Class SavedServer | EchoHub Documentation",
- "summary": "Class SavedServer Namespace EchoHub.Client.Config Assembly EchoHub.Client.dll public class SavedServer Inheritance object SavedServer Inherited Members object.GetType() object.MemberwiseClone() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors SavedServer() public SavedServer() Properties LastConnected public DateTimeOffset LastConnected { get; set; } Property Value DateTimeOffset Name public required string Name { get; set; } Property Value string RefreshToken public string? RefreshToken { get; set; } Property Value string RememberMe public bool RememberMe { get; set; } Property Value bool Url public required string Url { get; set; } Property Value string Username public string? Username { get; set; } Property Value string"
+ "summary": "Class SavedServer Namespace EchoHub.Client.Config Assembly EchoHub.Client.dll public class SavedServer Inheritance object SavedServer Inherited Members object.GetType() object.MemberwiseClone() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors SavedServer() public SavedServer() Properties ChannelKeys Cached room content keys for end-to-end encrypted channels on this server, keyed by channel name (base64). Like RefreshToken, these live only on the user's machine — the server never sees them. public Dictionary ChannelKeys { get; set; } Property Value Dictionary LastConnected public DateTimeOffset LastConnected { get; set; } Property Value DateTimeOffset Name public required string Name { get; set; } Property Value string RefreshToken public string? RefreshToken { get; set; } Property Value string RememberMe public bool RememberMe { get; set; } Property Value bool Url public required string Url { get; set; } Property Value string Username public string? Username { get; set; } Property Value string"
},
"api/client/EchoHub.Client.Config.html": {
"href": "api/client/EchoHub.Client.Config.html",
@@ -57,7 +57,7 @@
"api/client/EchoHub.Client.Services.ApiClient.html": {
"href": "api/client/EchoHub.Client.Services.ApiClient.html",
"title": "Class ApiClient | EchoHub Documentation",
- "summary": "Class ApiClient Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll public sealed class ApiClient : IDisposable Inheritance object ApiClient Implements IDisposable Inherited Members object.GetType() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors ApiClient(string) public ApiClient(string baseUrl) Parameters baseUrl string Properties BaseUrl public string BaseUrl { get; } Property Value string RefreshToken public string? RefreshToken { get; } Property Value string Token public string? Token { get; } Property Value string Methods AssignRoleAsync(string, ServerRole) public Task AssignRoleAsync(string username, ServerRole role) Parameters username string role ServerRole Returns Task BanUserAsync(string, string?) public Task BanUserAsync(string username, string? reason = null) Parameters username string reason string Returns Task CreateChannelAsync(string, string?, bool) public Task CreateChannelAsync(string name, string? topic = null, bool isPublic = true) Parameters name string topic string isPublic bool Returns Task DeleteChannelAsync(string) public Task DeleteChannelAsync(string channelName) Parameters channelName string Returns Task DeleteMessageAsync(Guid) public Task DeleteMessageAsync(Guid messageId) Parameters messageId Guid Returns Task Dispose() public void Dispose() DownloadFileToTempAsync(string, string) public Task DownloadFileToTempAsync(string relativeUrl, string fileName) Parameters relativeUrl string fileName string Returns Task GetChannelsAsync() public Task> GetChannelsAsync() Returns Task> GetEncryptionKeyAsync() public Task GetEncryptionKeyAsync() Returns Task GetServerInfoAsync() public Task GetServerInfoAsync() Returns Task GetUserProfileAsync(string) public Task GetUserProfileAsync(string username) Parameters username string Returns Task GetValidTokenAsync() Returns a valid access token, refreshing if expired. Used by EchoHubConnection for SignalR token provider. public Task GetValidTokenAsync() Returns Task KickUserAsync(string, string?) public Task KickUserAsync(string username, string? reason = null) Parameters username string reason string Returns Task LoginAsync(string, string) public Task LoginAsync(string username, string password) Parameters username string password string Returns Task LoginWithRefreshTokenAsync(string) public Task LoginWithRefreshTokenAsync(string refreshToken) Parameters refreshToken string Returns Task LogoutAsync() public Task LogoutAsync() Returns Task MuteUserAsync(string, int?, string?) public Task MuteUserAsync(string username, int? durationMinutes = null, string? reason = null) Parameters username string durationMinutes int? reason string Returns Task NukeChannelAsync(string) public Task NukeChannelAsync(string channelName) Parameters channelName string Returns Task RefreshTokenAsync() public Task RefreshTokenAsync() Returns Task RegisterAsync(string, string, string?) public Task RegisterAsync(string username, string password, string? displayName = null) Parameters username string password string displayName string Returns Task SendUrlAsync(string, string, string?) public Task SendUrlAsync(string channelName, string url, string? size = null) Parameters channelName string url string size string Returns Task UnbanUserAsync(string) public Task UnbanUserAsync(string username) Parameters username string Returns Task UnmuteUserAsync(string) public Task UnmuteUserAsync(string username) Parameters username string Returns Task UpdateChannelTopicAsync(string, string?) public Task UpdateChannelTopicAsync(string channelName, string? topic) Parameters channelName string topic string Returns Task UpdateProfileAsync(UpdateProfileRequest) public Task UpdateProfileAsync(UpdateProfileRequest request) Parameters request UpdateProfileRequest Returns Task UploadAvatarAsync(Stream, string) public Task UploadAvatarAsync(Stream imageStream, string fileName) Parameters imageStream Stream fileName string Returns Task UploadFileAsync(string, Stream, string, string?) public Task UploadFileAsync(string channelName, Stream fileStream, string fileName, string? size = null) Parameters channelName string fileStream Stream fileName string size string Returns Task Events OnTokensRefreshed public event Action? OnTokensRefreshed Event Type Action"
+ "summary": "Class ApiClient Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll public sealed class ApiClient : IDisposable Inheritance object ApiClient Implements IDisposable Inherited Members object.GetType() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors ApiClient(string) public ApiClient(string baseUrl) Parameters baseUrl string Properties BaseUrl public string BaseUrl { get; } Property Value string RefreshToken public string? RefreshToken { get; } Property Value string Token public string? Token { get; } Property Value string Methods AssignRoleAsync(string, ServerRole) public Task AssignRoleAsync(string username, ServerRole role) Parameters username string role ServerRole Returns Task BanUserAsync(string, string?) public Task BanUserAsync(string username, string? reason = null) Parameters username string reason string Returns Task CreateChannelAsync(string, string?, bool, string?, string?, string?) public Task CreateChannelAsync(string name, string? topic = null, bool isPublic = true, string? password = null, string? encryptionSalt = null, string? wrappedRoomKey = null) Parameters name string topic string isPublic bool password string encryptionSalt string wrappedRoomKey string Returns Task DeleteChannelAsync(string) public Task DeleteChannelAsync(string channelName) Parameters channelName string Returns Task DeleteMessageAsync(Guid) public Task DeleteMessageAsync(Guid messageId) Parameters messageId Guid Returns Task Dispose() public void Dispose() DownloadFileToTempAsync(string, string) public Task DownloadFileToTempAsync(string relativeUrl, string fileName) Parameters relativeUrl string fileName string Returns Task GetChannelCryptoAsync(string) Fetches a channel's public crypto metadata (whether it's E2E-encrypted and its key-derivation salt). Returns null when the channel doesn't exist. public Task GetChannelCryptoAsync(string channelName) Parameters channelName string Returns Task GetChannelsAsync() public Task> GetChannelsAsync() Returns Task> GetEncryptionKeyAsync() public Task GetEncryptionKeyAsync() Returns Task GetServerInfoAsync() public Task GetServerInfoAsync() Returns Task GetUserProfileAsync(string) public Task GetUserProfileAsync(string username) Parameters username string Returns Task GetValidTokenAsync() Returns a valid access token, refreshing if expired. Used by EchoHubConnection for SignalR token provider. public Task GetValidTokenAsync() Returns Task KickUserAsync(string, string?) public Task KickUserAsync(string username, string? reason = null) Parameters username string reason string Returns Task LoginAsync(string, string) public Task LoginAsync(string username, string password) Parameters username string password string Returns Task LoginWithRefreshTokenAsync(string) public Task LoginWithRefreshTokenAsync(string refreshToken) Parameters refreshToken string Returns Task LogoutAsync() public Task LogoutAsync() Returns Task MuteUserAsync(string, int?, string?) public Task MuteUserAsync(string username, int? durationMinutes = null, string? reason = null) Parameters username string durationMinutes int? reason string Returns Task NukeChannelAsync(string) public Task NukeChannelAsync(string channelName) Parameters channelName string Returns Task RefreshTokenAsync() public Task RefreshTokenAsync() Returns Task RegisterAsync(string, string, string?) public Task RegisterAsync(string username, string password, string? displayName = null) Parameters username string password string displayName string Returns Task RekeyChannelAsync(string, RekeyChannelRequest) public Task RekeyChannelAsync(string channelName, RekeyChannelRequest request) Parameters channelName string request RekeyChannelRequest Returns Task SendMessageWithAttachmentsAsync(string, string, IReadOnlyList, string?) Sends one message with optional text and one or more file attachments. For end-to-end encrypted channels each attachment carries a declared kind and a room-encrypted preview (empty when none); the caption is likewise room-encrypted. public Task SendMessageWithAttachmentsAsync(string channelName, string content, IReadOnlyList attachments, string? size = null) Parameters channelName string content string attachments IReadOnlyList size string Returns Task SendUrlAsync(string, string, string?) public Task SendUrlAsync(string channelName, string url, string? size = null) Parameters channelName string url string size string Returns Task UnbanUserAsync(string) public Task UnbanUserAsync(string username) Parameters username string Returns Task UnmuteUserAsync(string) public Task UnmuteUserAsync(string username) Parameters username string Returns Task UpdateChannelTopicAsync(string, string?) public Task UpdateChannelTopicAsync(string channelName, string? topic) Parameters channelName string topic string Returns Task UpdateProfileAsync(UpdateProfileRequest) public Task UpdateProfileAsync(UpdateProfileRequest request) Parameters request UpdateProfileRequest Returns Task UploadAvatarAsync(Stream, string) public Task UploadAvatarAsync(Stream imageStream, string fileName) Parameters imageStream Stream fileName string Returns Task Events OnTokensRefreshed public event Action? OnTokensRefreshed Event Type Action"
},
"api/client/EchoHub.Client.Services.AsyncRunner.html": {
"href": "api/client/EchoHub.Client.Services.AsyncRunner.html",
@@ -74,26 +74,66 @@
"title": "Class BackupInfo | EchoHub Documentation",
"summary": "Class BackupInfo Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll public record BackupInfo : IEquatable Inheritance object BackupInfo Implements IEquatable Inherited Members object.GetType() object.MemberwiseClone() object.Equals(object, object) object.ReferenceEquals(object, object) Constructors BackupInfo(BackupInfo) protected BackupInfo(BackupInfo original) Parameters original BackupInfo BackupInfo(string, string, DateTimeOffset) public BackupInfo(string Version, string AppDirectory, DateTimeOffset CreatedAt) Parameters Version string AppDirectory string CreatedAt DateTimeOffset Properties AppDirectory public string AppDirectory { get; init; } Property Value string CreatedAt public DateTimeOffset CreatedAt { get; init; } Property Value DateTimeOffset EqualityContract protected virtual Type EqualityContract { get; } Property Value Type Version public string Version { get; init; } Property Value string Methods Deconstruct(out string, out string, out DateTimeOffset) public void Deconstruct(out string Version, out string AppDirectory, out DateTimeOffset CreatedAt) Parameters Version string AppDirectory string CreatedAt DateTimeOffset Equals(BackupInfo?) public virtual bool Equals(BackupInfo? other) Parameters other BackupInfo Returns bool Equals(object?) public override bool Equals(object? obj) Parameters obj object Returns bool GetHashCode() public override int GetHashCode() Returns int PrintMembers(StringBuilder) protected virtual bool PrintMembers(StringBuilder builder) Parameters builder StringBuilder Returns bool ToString() public override string ToString() Returns string Operators operator ==(BackupInfo?, BackupInfo?) public static bool operator ==(BackupInfo? left, BackupInfo? right) Parameters left BackupInfo right BackupInfo Returns bool operator !=(BackupInfo?, BackupInfo?) public static bool operator !=(BackupInfo? left, BackupInfo? right) Parameters left BackupInfo right BackupInfo Returns bool"
},
+ "api/client/EchoHub.Client.Services.ChannelPasswordRequiredException.html": {
+ "href": "api/client/EchoHub.Client.Services.ChannelPasswordRequiredException.html",
+ "title": "Class ChannelPasswordRequiredException | EchoHub Documentation",
+ "summary": "Class ChannelPasswordRequiredException Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll Thrown when joining a channel fails because a password is required or incorrect. The UI catches this to prompt the user and retry. public sealed class ChannelPasswordRequiredException : Exception Inheritance object Exception ChannelPasswordRequiredException Inherited Members Exception.GetBaseException() Exception.ToString() Exception.GetType() Exception.TargetSite Exception.Message Exception.Data Exception.InnerException Exception.HelpLink Exception.Source Exception.HResult Exception.StackTrace object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors ChannelPasswordRequiredException(string, string) public ChannelPasswordRequiredException(string channelName, string message) Parameters channelName string message string Properties ChannelName public string ChannelName { get; } Property Value string"
+ },
"api/client/EchoHub.Client.Services.ClientEncryptionService.html": {
"href": "api/client/EchoHub.Client.Services.ClientEncryptionService.html",
"title": "Class ClientEncryptionService | EchoHub Documentation",
"summary": "Class ClientEncryptionService Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll Client-side encryption service. Uses the same AES-256-GCM format as the server so messages are encrypted end-to-end between client and server. public sealed class ClientEncryptionService : IMessageEncryptionService Inheritance object ClientEncryptionService Implements IMessageEncryptionService Inherited Members object.GetType() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors ClientEncryptionService() public ClientEncryptionService() Properties EncryptDatabaseEnabled Whether database content should be encrypted at rest (server setting). public bool EncryptDatabaseEnabled { get; } Property Value bool IsInitialized public bool IsInitialized { get; } Property Value bool Methods Decrypt(string) public string Decrypt(string content) Parameters content string Returns string DecryptNullable(string?) public string? DecryptNullable(string? value) Parameters value string Returns string Encrypt(string) public string Encrypt(string plaintext) Parameters plaintext string Returns string EncryptNullable(string?) public string? EncryptNullable(string? value) Parameters value string Returns string SetKey(string) Initialize with the server's encryption key (fetched after login). public void SetKey(string base64Key) Parameters base64Key string"
},
+ "api/client/EchoHub.Client.Services.ClipboardFiles.html": {
+ "href": "api/client/EchoHub.Client.Services.ClipboardFiles.html",
+ "title": "Class ClipboardFiles | EchoHub Documentation",
+ "summary": "Class ClipboardFiles Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll Reads file paths that live on the OS clipboard as a file list (e.g. after copying a file in Explorer/Finder/Nautilus), which terminals do not paste as text. Lets Ctrl+V attach a copied file directly instead of requiring the user to paste a raw path. public static class ClipboardFiles Inheritance object ClipboardFiles Inherited Members object.GetType() object.MemberwiseClone() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Methods TryGetFiles(out List) public static bool TryGetFiles(out List files) Parameters files List Returns bool"
+ },
"api/client/EchoHub.Client.Services.EchoHubConnection.html": {
"href": "api/client/EchoHub.Client.Services.EchoHubConnection.html",
"title": "Class EchoHubConnection | EchoHub Documentation",
- "summary": "Class EchoHubConnection Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll public sealed class EchoHubConnection : IAsyncDisposable Inheritance object EchoHubConnection Implements IAsyncDisposable Inherited Members object.GetType() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors EchoHubConnection(string, ApiClient, ClientEncryptionService) public EchoHubConnection(string serverUrl, ApiClient apiClient, ClientEncryptionService encryption) Parameters serverUrl string apiClient ApiClient encryption ClientEncryptionService Properties IsConnected public bool IsConnected { get; } Property Value bool Methods ConnectAsync() public Task ConnectAsync() Returns Task DisconnectAsync() public Task DisconnectAsync() Returns Task DisposeAsync() public ValueTask DisposeAsync() Returns ValueTask GetHistoryAsync(string, int, int) public Task> GetHistoryAsync(string channelName, int count = 100, int offset = 0) Parameters channelName string count int offset int Returns Task> GetOnlineUsersAsync(string) public Task> GetOnlineUsersAsync(string channelName) Parameters channelName string Returns Task> JoinChannelAsync(string) public Task> JoinChannelAsync(string channelName) Parameters channelName string Returns Task> LeaveChannelAsync(string) public Task LeaveChannelAsync(string channelName) Parameters channelName string Returns Task SendMessageAsync(string, string) public Task SendMessageAsync(string channelName, string content) Parameters channelName string content string Returns Task UpdateStatusAsync(UserStatus, string?) public Task UpdateStatusAsync(UserStatus status, string? statusMessage = null) Parameters status UserStatus statusMessage string Returns Task Events OnChannelNuked public event Action? OnChannelNuked Event Type Action OnChannelUpdated public event Action? OnChannelUpdated Event Type Action OnConnectionStateChanged public event Action? OnConnectionStateChanged Event Type Action OnError public event Action? OnError Event Type Action OnForceDisconnect public event Action? OnForceDisconnect Event Type Action OnMessageDeleted public event Action? OnMessageDeleted Event Type Action OnMessageReceived public event Action? OnMessageReceived Event Type Action OnReconnected public event Action? OnReconnected Event Type Action OnUserBanned public event Action? OnUserBanned Event Type Action OnUserJoined public event Action? OnUserJoined Event Type Action OnUserKicked public event Action? OnUserKicked Event Type Action OnUserLeft public event Action? OnUserLeft Event Type Action OnUserStatusChanged public event Action? OnUserStatusChanged Event Type Action"
+ "summary": "Class EchoHubConnection Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll public sealed class EchoHubConnection : IAsyncDisposable Inheritance object EchoHubConnection Implements IAsyncDisposable Inherited Members object.GetType() object.ToString() object.Equals(object) object.Equals(object, object) object.ReferenceEquals(object, object) object.GetHashCode() Constructors EchoHubConnection(string, ApiClient, ClientEncryptionService, RoomKeyStore) public EchoHubConnection(string serverUrl, ApiClient apiClient, ClientEncryptionService encryption, RoomKeyStore roomKeys) Parameters serverUrl string apiClient ApiClient encryption ClientEncryptionService roomKeys RoomKeyStore Fields LockedMessagePlaceholder public const string LockedMessagePlaceholder = \"[encrypted — rejoin this channel with its passphrase to unlock]\" Field Value string Properties IsConnected public bool IsConnected { get; } Property Value bool Methods ConnectAsync() public Task ConnectAsync() Returns Task DisconnectAsync() public Task DisconnectAsync() Returns Task DisposeAsync() public ValueTask DisposeAsync() Returns ValueTask GetHistoryAsync(string, int, int) public Task> GetHistoryAsync(string channelName, int count = 100, int offset = 0) Parameters channelName string count int offset int Returns Task> GetOnlineUsersAsync(string) public Task> GetOnlineUsersAsync(string channelName) Parameters channelName string Returns Task> JoinChannelAsync(string, string?) public Task JoinChannelAsync(string channelName, string? password = null) Parameters channelName string password string Returns Task LeaveChannelAsync(string) public Task LeaveChannelAsync(string channelName) Parameters channelName string Returns Task SendMessageAsync(string, string) public Task SendMessageAsync(string channelName, string content) Parameters channelName string content string Returns Task UpdateStatusAsync(UserStatus, string?) public Task UpdateStatusAsync(UserStatus status, string? statusMessage = null) Parameters status UserStatus statusMessage string Returns Task Events OnChannelNuked public event Action? OnChannelNuked Event Type Action OnChannelUpdated public event Action? OnChannelUpdated Event Type Action OnConnectionStateChanged public event Action? OnConnectionStateChanged Event Type Action OnError public event Action? OnError Event Type Action OnForceDisconnect public event Action? OnForceDisconnect Event Type Action OnMessageDeleted public event Action? OnMessageDeleted Event Type Action OnMessageReceived public event Action? OnMessageReceived Event Type Action OnReconnected public event Action? OnReconnected Event Type Action OnUserBanned public event Action? OnUserBanned Event Type Action OnUserJoined public event Action? OnUserJoined Event Type Action OnUserKicked public event Action? OnUserKicked Event Type Action OnUserLeft public event Action? OnUserLeft Event Type Action OnUserStatusChanged public event Action? OnUserStatusChanged Event Type Action"
+ },
+ "api/client/EchoHub.Client.Services.FolderPickResult.html": {
+ "href": "api/client/EchoHub.Client.Services.FolderPickResult.html",
+ "title": "Class FolderPickResult | EchoHub Documentation",
+ "summary": "Class FolderPickResult Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll public sealed record FolderPickResult : IEquatable Inheritance object FolderPickResult Implements IEquatable Inherited Members object.GetType() object.Equals(object, object) object.ReferenceEquals(object, object) Constructors FolderPickResult(PickerOutcome, string?) public FolderPickResult(PickerOutcome Outcome, string? Path) Parameters Outcome PickerOutcome Path string Properties Outcome public PickerOutcome Outcome { get; init; } Property Value PickerOutcome Path public string? Path { get; init; } Property Value string Methods Deconstruct(out PickerOutcome, out string?) public void Deconstruct(out PickerOutcome Outcome, out string? Path) Parameters Outcome PickerOutcome Path string Equals(FolderPickResult?) public bool Equals(FolderPickResult? other) Parameters other FolderPickResult Returns bool Equals(object?) public override bool Equals(object? obj) Parameters obj object Returns bool GetHashCode() public override int GetHashCode() Returns int ToString() public override string ToString() Returns string Operators operator ==(FolderPickResult?, FolderPickResult?) public static bool operator ==(FolderPickResult? left, FolderPickResult? right) Parameters left FolderPickResult right FolderPickResult Returns bool operator !=(FolderPickResult?, FolderPickResult?) public static bool operator !=(FolderPickResult? left, FolderPickResult? right) Parameters left FolderPickResult right FolderPickResult Returns bool"
+ },
+ "api/client/EchoHub.Client.Services.JoinOutcome.html": {
+ "href": "api/client/EchoHub.Client.Services.JoinOutcome.html",
+ "title": "Class JoinOutcome | EchoHub Documentation",
+ "summary": "Class JoinOutcome Namespace EchoHub.Client.Services Assembly EchoHub.Client.dll Result of joining a channel: decrypted history plus, for end-to-end encrypted channels, the key envelope needed to unlock the room content key. public sealed record JoinOutcome : IEquatable Inheritance object JoinOutcome Implements IEquatable Inherited Members object.GetType() object.Equals(object, object) object.ReferenceEquals(object, object) Constructors JoinOutcome(List, string?, string?) Result of joining a channel: decrypted history plus, for end-to-end encrypted channels, the key envelope needed to unlock the room content key. public JoinOutcome(List History, string? EncryptionSalt, string? WrappedRoomKey) Parameters History List EncryptionSalt string WrappedRoomKey string Properties EncryptionSalt public string? EncryptionSalt { get; init; } Property Value string History public List History { get; init; } Property Value List WrappedRoomKey public string? WrappedRoomKey { get; init; } Property Value string Methods Deconstruct(out List, out string?, out string?) public void Deconstruct(out List