about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--.idea/.idea.MatrixRoomUtils/.idea/vcs.xml1
m---------LibMatrix0
-rw-r--r--MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs46
-rw-r--r--MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs28
-rw-r--r--MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs17
-rw-r--r--MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs35
-rw-r--r--MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs12
-rw-r--r--MatrixRoomUtils.Bot/Bot/Interfaces/ICommand.cs12
-rw-r--r--MatrixRoomUtils.Bot/Bot/MRUBot.cs115
-rw-r--r--MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs12
-rw-r--r--MatrixRoomUtils.Bot/MatrixRoomUtils.Bot.csproj35
-rw-r--r--MatrixRoomUtils.Bot/Program.cs29
-rw-r--r--MatrixRoomUtils.Bot/Properties/launchSettings.json26
-rw-r--r--MatrixRoomUtils.Bot/appsettings.Development.json9
-rw-r--r--MatrixRoomUtils.Bot/appsettings.json13
-rw-r--r--MatrixRoomUtils.Core/AuthenticatedHomeServer.cs175
-rw-r--r--MatrixRoomUtils.Core/EventIdResponse.cs8
-rw-r--r--MatrixRoomUtils.Core/Extensions/ClassCollector.cs22
-rw-r--r--MatrixRoomUtils.Core/Extensions/DictionaryExtensions.cs33
-rw-r--r--MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs76
-rw-r--r--MatrixRoomUtils.Core/Extensions/IEnumerableExtensions.cs9
-rw-r--r--MatrixRoomUtils.Core/Extensions/JsonElementExtensions.cs151
-rw-r--r--MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs16
-rw-r--r--MatrixRoomUtils.Core/Extensions/StringExtensions.cs13
-rw-r--r--MatrixRoomUtils.Core/Filters/LocalRoomQueryFilter.cs28
-rw-r--r--MatrixRoomUtils.Core/Filters/SyncFilter.cs66
-rw-r--r--MatrixRoomUtils.Core/Helpers/MediaResolver.cs6
-rw-r--r--MatrixRoomUtils.Core/Helpers/SyncHelper.cs238
-rw-r--r--MatrixRoomUtils.Core/Interfaces/IHomeServer.cs31
-rw-r--r--MatrixRoomUtils.Core/Interfaces/IStateEventType.cs5
-rw-r--r--MatrixRoomUtils.Core/Interfaces/Services/IStorageProvider.cs58
-rw-r--r--MatrixRoomUtils.Core/MatrixException.cs59
-rw-r--r--MatrixRoomUtils.Core/MatrixRoomUtils.Core.csproj14
-rw-r--r--MatrixRoomUtils.Core/MessagesResponse.cs19
-rw-r--r--MatrixRoomUtils.Core/RemoteHomeServer.cs16
-rw-r--r--MatrixRoomUtils.Core/Responses/Admin/AdminRoomDeleteRequest.cs18
-rw-r--r--MatrixRoomUtils.Core/Responses/Admin/AdminRoomListingResult.cs64
-rw-r--r--MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs76
-rw-r--r--MatrixRoomUtils.Core/Responses/CreationContentBaseType.cs18
-rw-r--r--MatrixRoomUtils.Core/Responses/LoginResponse.cs17
-rw-r--r--MatrixRoomUtils.Core/Responses/StateEventResponse.cs48
-rw-r--r--MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs187
-rw-r--r--MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs28
-rw-r--r--MatrixRoomUtils.Core/Services/HomeserverProviderService.cs97
-rw-r--r--MatrixRoomUtils.Core/Services/HomeserverResolverService.cs87
-rw-r--r--MatrixRoomUtils.Core/Services/ServiceInstaller.cs30
-rw-r--r--MatrixRoomUtils.Core/Services/TieredStorageService.cs13
-rw-r--r--MatrixRoomUtils.Core/StateEvent.cs120
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs11
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs26
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs13
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessEventData.cs16
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityEventData.cs11
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/JoinRulesEventData.cs18
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs56
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs17
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponseEventData.cs13
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs11
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs28
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs27
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs15
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs29
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMessageEventData.cs19
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs11
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs11
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPowerLevelEventData.cs56
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs12
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs11
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLEventData.cs17
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs15
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceParentEventData.cs14
-rw-r--r--MatrixRoomUtils.Core/UserIdAndReason.cs10
-rw-r--r--MatrixRoomUtils.DebugDataValidationApi/Controllers/ValidationController.cs26
-rw-r--r--MatrixRoomUtils.DebugDataValidationApi/MatrixRoomUtils.DebugDataValidationApi.csproj19
-rw-r--r--MatrixRoomUtils.DebugDataValidationApi/Program.cs32
-rw-r--r--MatrixRoomUtils.DebugDataValidationApi/Properties/launchSettings.json41
-rw-r--r--MatrixRoomUtils.DebugDataValidationApi/appsettings.Development.json11
-rw-r--r--MatrixRoomUtils.DebugDataValidationApi/appsettings.json9
-rw-r--r--MatrixRoomUtils.Desktop/App.axaml.cs2
-rw-r--r--MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs8
-rw-r--r--MatrixRoomUtils.Desktop/FileStorageProvider.cs4
-rw-r--r--MatrixRoomUtils.Desktop/MRUStorageWrapper.cs6
-rw-r--r--MatrixRoomUtils.Desktop/MainWindow.axaml.cs6
-rw-r--r--MatrixRoomUtils.Desktop/MatrixRoomUtils.Desktop.csproj2
-rw-r--r--MatrixRoomUtils.Desktop/RoomInfo.cs7
-rw-r--r--MatrixRoomUtils.Web/Classes/LocalStorageProviderService.cs6
-rw-r--r--MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs6
-rw-r--r--MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs10
-rw-r--r--MatrixRoomUtils.Web/Classes/RoomCreationTemplates/IRoomCreationTemplate.cs4
-rw-r--r--MatrixRoomUtils.Web/Classes/RoomInfo.cs7
-rw-r--r--MatrixRoomUtils.Web/Classes/SessionStorageProviderService.cs8
-rw-r--r--MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj2
-rw-r--r--MatrixRoomUtils.Web/Pages/DebugTools.razor5
-rw-r--r--MatrixRoomUtils.Web/Pages/DevOptions.razor3
-rw-r--r--MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor9
-rw-r--r--MatrixRoomUtils.Web/Pages/Index.razor5
-rw-r--r--MatrixRoomUtils.Web/Pages/InvalidSession.razor4
-rw-r--r--MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor10
-rw-r--r--MatrixRoomUtils.Web/Pages/LoginPage.razor6
-rw-r--r--MatrixRoomUtils.Web/Pages/MediaLocator.razor3
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/Create.razor10
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/Index.razor10
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor10
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/Space.razor4
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor5
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor5
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor5
-rw-r--r--MatrixRoomUtils.Web/Program.cs4
-rw-r--r--MatrixRoomUtils.Web/Shared/InlineUserItem.razor8
-rw-r--r--MatrixRoomUtils.Web/Shared/ModalWindow.razor1
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomList.razor7
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor5
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor3
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListItem.razor9
-rw-r--r--MatrixRoomUtils.Web/Shared/SimpleComponents/DictionaryEditor.razor3
-rw-r--r--MatrixRoomUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor3
-rw-r--r--MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor6
-rw-r--r--MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMessageItem.razor2
-rw-r--r--MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineRoomCreateItem.razor4
-rw-r--r--MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineUnknownItem.razor1
-rw-r--r--MatrixRoomUtils.Web/Shared/UserListItem.razor11
-rw-r--r--MatrixRoomUtils.Web/_Imports.razor5
-rw-r--r--MatrixRoomUtils.Web/deps.nix49
-rwxr-xr-xMatrixRoomUtils.sln41
-rw-r--r--flake.lock6
-rw-r--r--flake.nix10
-rw-r--r--global.json7
-rwxr-xr-xmkdeps31
-rwxr-xr-xnuget-to-nix.sh88
130 files changed, 335 insertions, 2985 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..0620b64
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "LibMatrix"]
+	path = LibMatrix
+	url = https://git.rory.gay/matrix/LibMatrix.git
diff --git a/.idea/.idea.MatrixRoomUtils/.idea/vcs.xml b/.idea/.idea.MatrixRoomUtils/.idea/vcs.xml
index 94a25f7..4720c89 100644
--- a/.idea/.idea.MatrixRoomUtils/.idea/vcs.xml
+++ b/.idea/.idea.MatrixRoomUtils/.idea/vcs.xml
@@ -2,5 +2,6 @@
 <project version="4">
   <component name="VcsDirectoryMappings">
     <mapping directory="$PROJECT_DIR$" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/MatrixRoomUtils.Core" vcs="Git" />
   </component>
 </project>
\ No newline at end of file
diff --git a/LibMatrix b/LibMatrix
new file mode 160000
+Subproject 8fdc48e5b21b1eea61534b181585858727500f3
diff --git a/MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs b/MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs
deleted file mode 100644
index 79757ae..0000000
--- a/MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using MatrixRoomUtils.Bot.Bot.Interfaces;
-
-namespace MatrixRoomUtils.Bot.Bot.Commands;
-
-public class CmdCommand : ICommand {
-    public string Name { get; } = "cmd";
-    public string Description { get; } = "Runs a command on the host system";
-
-    public async Task<bool> CanInvoke(CommandContext ctx) {
-        return ctx.MessageEvent.Sender.EndsWith(":rory.gay");
-    }
-
-    public async Task Invoke(CommandContext ctx) {
-        var cmd = "\"";
-        foreach (var arg in ctx.Args) cmd += arg + " ";
-
-        cmd = cmd.Trim();
-        cmd += "\"";
-
-        await ctx.Room.SendMessageEventAsync("m.room.message", new() {
-            Body = $"Command being executed: `{cmd}`"
-        });
-
-        var output = ArcaneLibs.Util.GetCommandOutputSync(
-                Environment.OSVersion.Platform == PlatformID.Unix ? "/bin/sh" : "cmd.exe",
-                (Environment.OSVersion.Platform == PlatformID.Unix ? "-c " : "/c ") + cmd)
-            .Replace("`", "\\`")
-            .Split("\n").ToList();
-        foreach (var _out in output) Console.WriteLine($"{_out.Length:0000} {_out}");
-
-        var msg = "";
-        while (output.Count > 0) {
-            Console.WriteLine("Adding: " + output[0]);
-            msg += output[0] + "\n";
-            output.RemoveAt(0);
-            if ((output.Count > 0 && (msg + output[0]).Length > 64000) || output.Count == 0) {
-                await ctx.Room.SendMessageEventAsync("m.room.message", new() {
-                    FormattedBody = $"```ansi\n{msg}\n```",
-                    // Body = Markdig.Markdown.ToHtml(msg),
-                    Format = "org.matrix.custom.html"
-                });
-                msg = "";
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs b/MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs
deleted file mode 100644
index 6db10ae..0000000
--- a/MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Text;
-using MatrixRoomUtils.Bot.Bot.Interfaces;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace MatrixRoomUtils.Bot.Bot.Commands; 
-
-public class HelpCommand : ICommand {
-    private readonly IServiceProvider _services;
-    public HelpCommand(IServiceProvider services) {
-        _services = services;
-    }
-
-    public string Name { get; } = "help";
-    public string Description { get; } = "Displays this help message";
-
-    public async Task Invoke(CommandContext ctx) {
-        var sb = new StringBuilder();
-        sb.AppendLine("Available commands:");
-        var commands = _services.GetServices<ICommand>().ToList();
-        foreach (var command in commands) {
-            sb.AppendLine($"- {command.Name}: {command.Description}");
-        }
-
-        await ctx.Room.SendMessageEventAsync("m.room.message", new() {
-            Body = sb.ToString(),
-        });
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs b/MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs
deleted file mode 100644
index 061ca53..0000000
--- a/MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using MatrixRoomUtils.Bot.Bot.Interfaces;
-
-namespace MatrixRoomUtils.Bot.Bot.Commands; 
-
-public class PingCommand : ICommand {
-    public PingCommand() {
-    }
-
-    public string Name { get; } = "ping";
-    public string Description { get; } = "Pong!";
-
-    public async Task Invoke(CommandContext ctx) {
-        await ctx.Room.SendMessageEventAsync("m.room.message", new() {
-            Body = "pong!"
-        });
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs b/MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs
deleted file mode 100644
index c38591d..0000000
--- a/MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System.Text.Json;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces.Services;
-using Microsoft.Extensions.Logging;
-
-namespace MatrixRoomUtils.Bot.Bot; 
-
-public class FileStorageProvider : IStorageProvider {
-    private readonly ILogger<FileStorageProvider> _logger;
-
-    public string TargetPath { get; }
-
-    /// <summary>
-    /// Creates a new instance of <see cref="FileStorageProvider" />.
-    /// </summary>
-    /// <param name="targetPath"></param>
-    public FileStorageProvider(string targetPath) {
-        new Logger<FileStorageProvider>(new LoggerFactory()).LogInformation("test");
-        Console.WriteLine($"Initialised FileStorageProvider with path {targetPath}");
-        TargetPath = targetPath;
-        if(!Directory.Exists(targetPath)) {
-            Directory.CreateDirectory(targetPath);
-        }
-    }
-
-    public async Task SaveObjectAsync<T>(string key, T value) => await File.WriteAllTextAsync(Path.Join(TargetPath, key), ObjectExtensions.ToJson(value));
-
-    public async Task<T?> LoadObjectAsync<T>(string key) => JsonSerializer.Deserialize<T>(await File.ReadAllTextAsync(Path.Join(TargetPath, key)));
-
-    public async Task<bool> ObjectExistsAsync(string key) => File.Exists(Path.Join(TargetPath, key));
-
-    public async Task<List<string>> GetAllKeysAsync() => Directory.GetFiles(TargetPath).Select(Path.GetFileName).ToList();
-
-    public async Task DeleteObjectAsync(string key) => File.Delete(Path.Join(TargetPath, key));
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs b/MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs
deleted file mode 100644
index 94007a5..0000000
--- a/MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.RoomTypes;
-using MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-namespace MatrixRoomUtils.Bot.Bot.Interfaces;
-
-public class CommandContext {
-    public GenericRoom Room { get; set; }
-    public StateEventResponse MessageEvent { get; set; }
-    public string CommandName => (MessageEvent.TypedContent as RoomMessageEventData).Body.Split(' ')[0][1..];
-    public string[] Args => (MessageEvent.TypedContent as RoomMessageEventData).Body.Split(' ')[1..];
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/Bot/Interfaces/ICommand.cs b/MatrixRoomUtils.Bot/Bot/Interfaces/ICommand.cs
deleted file mode 100644
index 20805b1..0000000
--- a/MatrixRoomUtils.Bot/Bot/Interfaces/ICommand.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace MatrixRoomUtils.Bot.Bot.Interfaces; 
-
-public interface ICommand {
-    public string Name { get; }
-    public string Description { get; }
-
-    public Task<bool> CanInvoke(CommandContext ctx) {
-        return Task.FromResult(true);
-    }
-    
-    public Task Invoke(CommandContext ctx);
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/Bot/MRUBot.cs b/MatrixRoomUtils.Bot/Bot/MRUBot.cs
deleted file mode 100644
index bd24ec7..0000000
--- a/MatrixRoomUtils.Bot/Bot/MRUBot.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using MatrixRoomUtils.Bot.Bot.Interfaces;
-using MatrixRoomUtils.Core;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Services;
-using MatrixRoomUtils.Core.StateEventTypes.Spec;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-
-namespace MatrixRoomUtils.Bot.Bot;
-
-public class MRUBot : IHostedService {
-    private readonly HomeserverProviderService _homeserverProviderService;
-    private readonly ILogger<MRUBot> _logger;
-    private readonly MRUBotConfiguration _configuration;
-    private readonly IEnumerable<ICommand> _commands;
-
-    public MRUBot(HomeserverProviderService homeserverProviderService, ILogger<MRUBot> logger,
-        MRUBotConfiguration configuration, IServiceProvider services) {
-        logger.LogInformation("MRUBot hosted service instantiated!");
-        _homeserverProviderService = homeserverProviderService;
-        _logger = logger;
-        _configuration = configuration;
-        _logger.LogInformation("Getting commands...");
-        _commands = services.GetServices<ICommand>();
-        _logger.LogInformation($"Got {_commands.Count()} commands!");
-    }
-
-    /// <summary>Triggered when the application host is ready to start the service.</summary>
-    /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
-    [SuppressMessage("ReSharper", "FunctionNeverReturns")]
-    public async Task StartAsync(CancellationToken cancellationToken) {
-        Directory.GetFiles("bot_data/cache").ToList().ForEach(File.Delete);
-        AuthenticatedHomeServer hs;
-        try {
-            hs = await _homeserverProviderService.GetAuthenticatedWithToken(_configuration.Homeserver,
-                _configuration.AccessToken);
-        }
-        catch (Exception e) {
-            _logger.LogError(e.Message);
-            throw;
-        }
-
-        await (await hs.GetRoom("!DoHEdFablOLjddKWIp:rory.gay")).JoinAsync();
-
-        // foreach (var room in await hs.GetJoinedRooms()) {
-        //     if(room.RoomId is "!OGEhHVWSdvArJzumhm:matrix.org") continue;
-        //     foreach (var stateEvent in await room.GetStateAsync<List<StateEvent>>("")) {
-        //         var _ = stateEvent.GetType;
-        //     }
-        //     _logger.LogInformation($"Got room state for {room.RoomId}!");
-        // }
-
-        hs.SyncHelper.InviteReceivedHandlers.Add(async Task (args) => {
-            var inviteEvent =
-                args.Value.InviteState.Events.FirstOrDefault(x =>
-                    x.Type == "m.room.member" && x.StateKey == hs.WhoAmI.UserId);
-            _logger.LogInformation(
-                $"Got invite to {args.Key} by {inviteEvent.Sender} with reason: {(inviteEvent.TypedContent as RoomMemberEventData).Reason}");
-            if (inviteEvent.Sender.EndsWith(":rory.gay") || inviteEvent.Sender == "@mxidupwitch:the-apothecary.club" ) {
-                try {
-                    var senderProfile = await hs.GetProfile(inviteEvent.Sender);
-                    await (await hs.GetRoom(args.Key)).JoinAsync(reason: $"I was invited by {senderProfile.DisplayName ?? inviteEvent.Sender}!");
-                }
-                catch (Exception e) {
-                    _logger.LogError(e.ToString());
-                    await (await hs.GetRoom(args.Key)).LeaveAsync(reason: "I was unable to join the room: " + e);
-                }
-            }
-        });
-        hs.SyncHelper.TimelineEventHandlers.Add(async @event => {
-            _logger.LogInformation(
-                $"Got timeline event in {@event.RoomId}: {@event.ToJson(indent: false, ignoreNull: true)}");
-
-            var room = await hs.GetRoom(@event.RoomId);
-            // _logger.LogInformation(eventResponse.ToJson(indent: false));
-            if (@event is { Type: "m.room.message", TypedContent: RoomMessageEventData message }) {
-                if (message is { MessageType: "m.text" } && message.Body.StartsWith(_configuration.Prefix)) {
-
-                    var command = _commands.FirstOrDefault(x => x.Name == message.Body.Split(' ')[0][_configuration.Prefix.Length..]);
-                    if (command == null) {
-                        await room.SendMessageEventAsync("m.room.message",
-                            new RoomMessageEventData() {
-                                MessageType = "m.text",
-                                Body = "Command not found!"
-                            });
-                        return;
-                    }
-                    var ctx = new CommandContext() {
-                        Room = room,
-                        MessageEvent = @event
-                    };
-                    if (await command.CanInvoke(ctx)) {
-                        await command.Invoke(ctx);
-                    }
-                    else {
-                        await room.SendMessageEventAsync("m.room.message",
-                            new RoomMessageEventData() {
-                                MessageType = "m.text",
-                                Body = "You do not have permission to run this command!"
-                            });
-                    }
-                }
-            }
-        });
-        await hs.SyncHelper.RunSyncLoop(cancellationToken: cancellationToken);
-    }
-
-    /// <summary>Triggered when the application host is performing a graceful shutdown.</summary>
-    /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
-    public async Task StopAsync(CancellationToken cancellationToken) {
-        _logger.LogInformation("Shutting down bot!");
-    }
-}
diff --git a/MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs b/MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs
deleted file mode 100644
index 418eebb..0000000
--- a/MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using Microsoft.Extensions.Configuration;
-
-namespace MatrixRoomUtils.Bot.Bot; 
-
-public class MRUBotConfiguration {
-    public MRUBotConfiguration(IConfiguration config) {
-        config.GetRequiredSection("Bot").Bind(this);
-    }
-    public string Homeserver { get; set; } = "";
-    public string AccessToken { get; set; } = "";
-    public string Prefix { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/MatrixRoomUtils.Bot.csproj b/MatrixRoomUtils.Bot/MatrixRoomUtils.Bot.csproj
deleted file mode 100644
index d9b2931..0000000
--- a/MatrixRoomUtils.Bot/MatrixRoomUtils.Bot.csproj
+++ /dev/null
@@ -1,35 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">

-

-  <PropertyGroup>

-    <OutputType>Exe</OutputType>

-    <TargetFramework>net8.0</TargetFramework>

-    <LangVersion>preview</LangVersion>

-    <ImplicitUsings>enable</ImplicitUsings>

-    <Nullable>enable</Nullable>

-    <PublishAot>false</PublishAot>

-    <InvariantGlobalization>true</InvariantGlobalization>

-    <PublishTrimmed>true</PublishTrimmed>

-    <PublishReadyToRun>true</PublishReadyToRun>

-    <PublishSingleFile>true</PublishSingleFile>

-    <PublishReadyToRunShowWarnings>true</PublishReadyToRunShowWarnings>

-    <PublishTrimmedShowLinkerSizeComparison>true</PublishTrimmedShowLinkerSizeComparison>

-    <PublishTrimmedShowLinkerSizeComparisonWarnings>true</PublishTrimmedShowLinkerSizeComparisonWarnings>

-  </PropertyGroup>

-

-  <ItemGroup>

-    <ProjectReference Include="..\MatrixRoomUtils.Core\MatrixRoomUtils.Core.csproj" />

-  </ItemGroup>

-  

-  <ItemGroup>

-    <PackageReference Include="ArcaneLibs" Version="1.0.0-preview3020494760.012ed3f" />

-    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0-preview.5.23280.8" />

-  </ItemGroup>

-  <ItemGroup>

-    <Content Include="appsettings*.json">

-      <CopyToOutputDirectory>Always</CopyToOutputDirectory>

-    </Content>

-    <Content Update="appsettings.Local.emmalocal.json">

-      <CopyToOutputDirectory>Always</CopyToOutputDirectory>

-    </Content>

-  </ItemGroup>

-</Project>

diff --git a/MatrixRoomUtils.Bot/Program.cs b/MatrixRoomUtils.Bot/Program.cs
deleted file mode 100644
index 5dae843..0000000
--- a/MatrixRoomUtils.Bot/Program.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-// See https://aka.ms/new-console-template for more information

-

-using MatrixRoomUtils.Bot;

-using MatrixRoomUtils.Bot.Bot;

-using MatrixRoomUtils.Bot.Bot.Interfaces;

-using MatrixRoomUtils.Core.Extensions;

-using MatrixRoomUtils.Core.Services;

-using Microsoft.Extensions.DependencyInjection;

-using Microsoft.Extensions.Hosting;

-

-Console.WriteLine("Hello, World!");

-

-var host = Host.CreateDefaultBuilder(args).ConfigureServices((_, services) => {

-    services.AddScoped<TieredStorageService>(x =>

-        new(

-            cacheStorageProvider: new FileStorageProvider("bot_data/cache/"),

-            dataStorageProvider: new FileStorageProvider("bot_data/data/")

-        )

-    );

-    services.AddScoped<MRUBotConfiguration>();

-    services.AddRoryLibMatrixServices();

-    foreach (var commandClass in new ClassCollector<ICommand>().ResolveFromAllAccessibleAssemblies()) {

-        Console.WriteLine($"Adding command {commandClass.Name}");

-        services.AddScoped(typeof(ICommand), commandClass);

-    }

-    services.AddHostedService<MRUBot>();

-}).UseConsoleLifetime().Build();

-

-await host.RunAsync();
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/Properties/launchSettings.json b/MatrixRoomUtils.Bot/Properties/launchSettings.json
deleted file mode 100644
index 997e294..0000000
--- a/MatrixRoomUtils.Bot/Properties/launchSettings.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "$schema": "http://json.schemastore.org/launchsettings.json",
-  "profiles": {
-    "Default": {
-      "commandName": "Project",
-      "dotnetRunMessages": true,
-      "environmentVariables": {
-
-      }
-    },
-    "Development": {
-      "commandName": "Project",
-      "dotnetRunMessages": true,
-      "environmentVariables": {
-        "DOTNET_ENVIRONMENT": "Development"
-      }
-    },
-    "Local config": {
-      "commandName": "Project",
-      "dotnetRunMessages": true,
-      "environmentVariables": {
-        "DOTNET_ENVIRONMENT": "Local"
-      }
-    }
-  }
-}
diff --git a/MatrixRoomUtils.Bot/appsettings.Development.json b/MatrixRoomUtils.Bot/appsettings.Development.json
deleted file mode 100644
index 27bbd50..0000000
--- a/MatrixRoomUtils.Bot/appsettings.Development.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "Logging": {
-        "LogLevel": {
-            "Default": "Debug",
-            "System": "Information",
-            "Microsoft": "Information"
-        }
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Bot/appsettings.json b/MatrixRoomUtils.Bot/appsettings.json
deleted file mode 100644
index 5668b53..0000000
--- a/MatrixRoomUtils.Bot/appsettings.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "Logging": {
-        "LogLevel": {
-            "Default": "Debug",
-            "System": "Information",
-            "Microsoft": "Information"
-        }
-    },
-    "Bot": {
-        "Homeserver": "rory.gay",
-        "AccessToken": "syt_xxxxxxxxxxxxxxxxx"
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs
deleted file mode 100644
index fbbb99f..0000000
--- a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs
+++ /dev/null
@@ -1,175 +0,0 @@
-using System.Net.Http.Headers;
-using System.Net.Http.Json;
-using System.Text.Json;
-using System.Text.Json.Nodes;
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Filters;
-using MatrixRoomUtils.Core.Helpers;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.Responses.Admin;
-using MatrixRoomUtils.Core.RoomTypes;
-using MatrixRoomUtils.Core.Services;
-
-namespace MatrixRoomUtils.Core;
-
-public class AuthenticatedHomeServer : IHomeServer {
-    private readonly TieredStorageService _storage;
-    public readonly HomeserverAdminApi Admin;
-    public readonly SyncHelper SyncHelper;
-
-    public AuthenticatedHomeServer(TieredStorageService storage, string canonicalHomeServerDomain, string accessToken) {
-        _storage = storage;
-        AccessToken = accessToken.Trim();
-        HomeServerDomain = canonicalHomeServerDomain.Trim();
-        Admin = new HomeserverAdminApi(this);
-        SyncHelper = new SyncHelper(this, storage);
-        _httpClient = new MatrixHttpClient();
-    }
-
-    public WhoAmIResponse WhoAmI { get; set; } = null!;
-    public string UserId => WhoAmI.UserId;
-    public string AccessToken { get; set; }
-
-
-    public async Task<GenericRoom> GetRoom(string roomId) => new(this, roomId);
-
-    public async Task<List<GenericRoom>> GetJoinedRooms() {
-        var rooms = new List<GenericRoom>();
-        var roomQuery = await _httpClient.GetAsync("/_matrix/client/v3/joined_rooms");
-
-        var roomsJson = await roomQuery.Content.ReadFromJsonAsync<JsonElement>();
-        foreach (var room in roomsJson.GetProperty("joined_rooms").EnumerateArray()) rooms.Add(new GenericRoom(this, room.GetString()));
-
-        Console.WriteLine($"Fetched {rooms.Count} rooms");
-
-        return rooms;
-    }
-
-    public async Task<string> UploadFile(string fileName, Stream fileStream, string contentType = "application/octet-stream") {
-        var res = await _httpClient.PostAsync($"/_matrix/media/v3/upload?filename={fileName}", new StreamContent(fileStream));
-        if (!res.IsSuccessStatusCode) {
-            Console.WriteLine($"Failed to upload file: {await res.Content.ReadAsStringAsync()}");
-            throw new InvalidDataException($"Failed to upload file: {await res.Content.ReadAsStringAsync()}");
-        }
-
-        var resJson = await res.Content.ReadFromJsonAsync<JsonElement>();
-        return resJson.GetProperty("content_uri").GetString()!;
-    }
-
-    public async Task<GenericRoom> CreateRoom(CreateRoomRequest creationEvent) {
-        var res = await _httpClient.PostAsJsonAsync("/_matrix/client/v3/createRoom", creationEvent);
-        if (!res.IsSuccessStatusCode) {
-            Console.WriteLine($"Failed to create room: {await res.Content.ReadAsStringAsync()}");
-            throw new InvalidDataException($"Failed to create room: {await res.Content.ReadAsStringAsync()}");
-        }
-
-        return await GetRoom((await res.Content.ReadFromJsonAsync<JsonObject>())!["room_id"]!.ToString());
-    }
-
-    public class HomeserverAdminApi {
-        private readonly AuthenticatedHomeServer _authenticatedHomeServer;
-
-        public HomeserverAdminApi(AuthenticatedHomeServer authenticatedHomeServer) => _authenticatedHomeServer = authenticatedHomeServer;
-
-        public async IAsyncEnumerable<AdminRoomListingResult.AdminRoomListingResultRoom> SearchRoomsAsync(int limit = int.MaxValue, string orderBy = "name", string dir = "f", string? searchTerm = null, LocalRoomQueryFilter? localFilter = null) {
-            AdminRoomListingResult? res = null;
-            var i = 0;
-            int? totalRooms = null;
-            do {
-                var url = $"/_synapse/admin/v1/rooms?limit={Math.Min(limit, 100)}&dir={dir}&order_by={orderBy}";
-                if (!string.IsNullOrEmpty(searchTerm)) url += $"&search_term={searchTerm}";
-
-                if (res?.NextBatch is not null) url += $"&from={res.NextBatch}";
-
-                Console.WriteLine($"--- ADMIN Querying Room List with URL: {url} - Already have {i} items... ---");
-
-                res = await _authenticatedHomeServer._httpClient.GetFromJsonAsync<AdminRoomListingResult>(url);
-                totalRooms ??= res?.TotalRooms;
-                Console.WriteLine(res.ToJson(false));
-                foreach (var room in res.Rooms) {
-                    if (localFilter is not null) {
-                        if (!room.RoomId.Contains(localFilter.RoomIdContains)) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if (!room.Name?.Contains(localFilter.NameContains) == true) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if (!room.CanonicalAlias?.Contains(localFilter.CanonicalAliasContains) == true) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if (!room.Version.Contains(localFilter.VersionContains)) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if (!room.Creator.Contains(localFilter.CreatorContains)) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if (!room.Encryption?.Contains(localFilter.EncryptionContains) == true) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if (!room.JoinRules?.Contains(localFilter.JoinRulesContains) == true) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if(!room.GuestAccess?.Contains(localFilter.GuestAccessContains) == true) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if(!room.HistoryVisibility?.Contains(localFilter.HistoryVisibilityContains) == true) {
-                            totalRooms--;
-                            continue;
-                        }
-                        
-                        if(localFilter.CheckFederation && room.Federatable != localFilter.Federatable) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if(localFilter.CheckPublic && room.Public != localFilter.Public) {
-                            totalRooms--;
-                            continue;
-                        }
-                        
-                        if(room.JoinedMembers < localFilter.JoinedMembersGreaterThan || room.JoinedMembers > localFilter.JoinedMembersLessThan) {
-                            totalRooms--;
-                            continue;
-                        }
-                        if(room.JoinedLocalMembers < localFilter.JoinedLocalMembersGreaterThan || room.JoinedLocalMembers > localFilter.JoinedLocalMembersLessThan) {
-                            totalRooms--;
-                            continue;
-                        }
-                    }
-                    // if (contentSearch is not null && !string.IsNullOrEmpty(contentSearch) &&
-                    //     !(
-                    //         room.Name?.Contains(contentSearch, StringComparison.InvariantCultureIgnoreCase) == true ||
-                    //         room.CanonicalAlias?.Contains(contentSearch, StringComparison.InvariantCultureIgnoreCase) == true ||
-                    //         room.Creator?.Contains(contentSearch, StringComparison.InvariantCultureIgnoreCase) == true
-                    //     )
-                    //    ) {
-                    //     totalRooms--;
-                    //     continue;
-                    // }
-
-                    i++;
-                    yield return room;
-                }
-            } while (i < Math.Min(limit, totalRooms ?? limit));
-        }
-    }
-}
-
-public class WhoAmIResponse {
-    [JsonPropertyName("user_id")]
-    public string UserId { get; set; } = null!;
-
-    [JsonPropertyName("device_id")]
-    public string? DeviceId { get; set; }
-    [JsonPropertyName("is_guest")]
-    public bool? IsGuest { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/EventIdResponse.cs b/MatrixRoomUtils.Core/EventIdResponse.cs
deleted file mode 100644
index 77dc7f8..0000000
--- a/MatrixRoomUtils.Core/EventIdResponse.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace MatrixRoomUtils.Core;
-
-public class EventIdResponse {
-    [JsonPropertyName("event_id")]
-    public string EventId { get; set; } = null!;
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Extensions/ClassCollector.cs b/MatrixRoomUtils.Core/Extensions/ClassCollector.cs
deleted file mode 100644
index d4ba838..0000000
--- a/MatrixRoomUtils.Core/Extensions/ClassCollector.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Reflection;
-
-namespace MatrixRoomUtils.Core.Extensions;
-
-public class ClassCollector<T> where T : class {
-    static ClassCollector() {
-        if (!typeof(T).IsInterface)
-            throw new ArgumentException(
-                $"ClassCollector<T> must be used with an interface type. Passed type: {typeof(T).Name}");
-    }
-
-    public List<Type> ResolveFromAllAccessibleAssemblies() => AppDomain.CurrentDomain.GetAssemblies().SelectMany(ResolveFromAssembly).ToList();
-
-    public List<Type> ResolveFromObjectReference(object obj) => ResolveFromTypeReference(obj.GetType());
-
-    public List<Type> ResolveFromTypeReference(Type t) => Assembly.GetAssembly(t)?.GetReferencedAssemblies().SelectMany(ResolveFromAssemblyName).ToList() ?? new List<Type>();
-
-    public List<Type> ResolveFromAssemblyName(AssemblyName assemblyName) => ResolveFromAssembly(Assembly.Load(assemblyName));
-
-    public List<Type> ResolveFromAssembly(Assembly assembly) => assembly.GetTypes()
-        .Where(x => x is { IsClass: true, IsAbstract: false } && x.GetInterfaces().Contains(typeof(T))).ToList();
-}
diff --git a/MatrixRoomUtils.Core/Extensions/DictionaryExtensions.cs b/MatrixRoomUtils.Core/Extensions/DictionaryExtensions.cs
deleted file mode 100644
index 78bbdfa..0000000
--- a/MatrixRoomUtils.Core/Extensions/DictionaryExtensions.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-namespace MatrixRoomUtils.Core.Extensions;
-
-public static class DictionaryExtensions {
-    public static bool ChangeKey<TKey, TValue>(this IDictionary<TKey, TValue> dict,
-        TKey oldKey, TKey newKey) {
-        TValue value;
-        if (!dict.Remove(oldKey, out value))
-            return false;
-
-        dict[newKey] = value; // or dict.Add(newKey, value) depending on ur comfort
-        return true;
-    }
-
-    public static Y GetOrCreate<X, Y>(this IDictionary<X, Y> dict, X key) where Y : new() {
-        if (dict.TryGetValue(key, out var value)) {
-            return value;
-        }
-
-        value = new Y();
-        dict.Add(key, value);
-        return value;
-    }
-
-    public static Y GetOrCreate<X, Y>(this IDictionary<X, Y> dict, X key, Func<X, Y> valueFactory) {
-        if (dict.TryGetValue(key, out var value)) {
-            return value;
-        }
-
-        value = valueFactory(key);
-        dict.Add(key, value);
-        return value;
-    }
-}
diff --git a/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs b/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs
deleted file mode 100644
index 009338a..0000000
--- a/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System.Net.Http.Headers;
-using System.Reflection;
-using System.Text.Json;
-
-namespace MatrixRoomUtils.Core.Extensions;
-
-public static class HttpClientExtensions {
-    public static async Task<bool> CheckSuccessStatus(this HttpClient hc, string url) {
-        //cors causes failure, try to catch
-        try {
-            var resp = await hc.GetAsync(url);
-            return resp.IsSuccessStatusCode;
-        }
-        catch (Exception e) {
-            Console.WriteLine($"Failed to check success status: {e.Message}");
-            return false;
-        }
-    }
-}
-
-public class MatrixHttpClient : HttpClient {
-    public override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
-        CancellationToken cancellationToken) {
-        Console.WriteLine($"Sending request to {request.RequestUri}");
-        try {
-            HttpRequestOptionsKey<bool> WebAssemblyEnableStreamingResponseKey =
-                new HttpRequestOptionsKey<bool>("WebAssemblyEnableStreamingResponse");
-            request.Options.Set(WebAssemblyEnableStreamingResponseKey, true);
-        }
-        catch (Exception e) {
-            Console.WriteLine("Failed to set browser response streaming:");
-            Console.WriteLine(e);
-        }
-
-        var a = await base.SendAsync(request, cancellationToken);
-        if (!a.IsSuccessStatusCode) {
-            var content = await a.Content.ReadAsStringAsync(cancellationToken);
-            if (content.StartsWith('{')) {
-                var ex = JsonSerializer.Deserialize<MatrixException>(content);
-                ex.RawContent = content;
-                // Console.WriteLine($"Failed to send request: {ex}");
-                if (ex?.RetryAfterMs is not null) {
-                    await Task.Delay(ex.RetryAfterMs.Value, cancellationToken);
-                    typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance)
-                        ?.SetValue(request, 0);
-                    return await SendAsync(request, cancellationToken);
-                }
-
-                throw ex!;
-            }
-
-            throw new InvalidDataException("Encountered invalid data:\n" + content);
-        }
-
-        return a;
-    }
-
-    // GetFromJsonAsync
-    public async Task<T> GetFromJsonAsync<T>(string requestUri, CancellationToken cancellationToken = default) {
-        var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
-        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
-        var response = await SendAsync(request, cancellationToken);
-        response.EnsureSuccessStatusCode();
-        await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
-        return await JsonSerializer.DeserializeAsync<T>(responseStream, cancellationToken: cancellationToken);
-    }
-
-    // GetStreamAsync
-    public async Task<Stream> GetStreamAsync(string requestUri, CancellationToken cancellationToken = default) {
-        var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
-        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
-        var response = await SendAsync(request, cancellationToken);
-        response.EnsureSuccessStatusCode();
-        return await response.Content.ReadAsStreamAsync(cancellationToken);
-    }
-}
diff --git a/MatrixRoomUtils.Core/Extensions/IEnumerableExtensions.cs b/MatrixRoomUtils.Core/Extensions/IEnumerableExtensions.cs
deleted file mode 100644
index 8994529..0000000
--- a/MatrixRoomUtils.Core/Extensions/IEnumerableExtensions.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.Extensions;
-
-[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
-public class MatrixEventAttribute : Attribute {
-    public string EventName { get; set; }
-    public bool Legacy { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Extensions/JsonElementExtensions.cs b/MatrixRoomUtils.Core/Extensions/JsonElementExtensions.cs
deleted file mode 100644
index 7701c9e..0000000
--- a/MatrixRoomUtils.Core/Extensions/JsonElementExtensions.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-using System.Text.Json;
-using System.Text.Json.Nodes;
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Responses;
-
-namespace MatrixRoomUtils.Core.Extensions;
-
-public static class JsonElementExtensions {
-    public static bool FindExtraJsonElementFields(this JsonElement obj, Type objectType, string objectPropertyName) {
-        if (objectPropertyName == "content" && objectType == typeof(JsonObject))
-            objectType = typeof(StateEventResponse);
-        // if (t == typeof(JsonNode))
-        //     return false;
-
-        Console.WriteLine($"{objectType.Name} {objectPropertyName}");
-        bool unknownPropertyFound = false;
-        var mappedPropsDict = objectType.GetProperties()
-            .Where(x => x.GetCustomAttribute<JsonPropertyNameAttribute>() is not null)
-            .ToDictionary(x => x.GetCustomAttribute<JsonPropertyNameAttribute>()!.Name, x => x);
-        objectType.GetProperties().Where(x => !mappedPropsDict.ContainsKey(x.Name))
-            .ToList().ForEach(x => mappedPropsDict.TryAdd(x.Name, x));
-
-        foreach (var field in obj.EnumerateObject()) {
-            if (mappedPropsDict.TryGetValue(field.Name, out var mappedProperty)) {
-                //dictionary
-                if (mappedProperty.PropertyType.IsGenericType &&
-                    mappedProperty.PropertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) {
-                    unknownPropertyFound |= _checkDictionary(field, objectType, mappedProperty.PropertyType);
-                    continue;
-                }
-
-                if (mappedProperty.PropertyType.IsGenericType &&
-                    mappedProperty.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) {
-                    unknownPropertyFound |= _checkList(field, objectType, mappedProperty.PropertyType);
-                    continue;
-                }
-
-                if (field.Name == "content" && (objectType == typeof(StateEventResponse) || objectType == typeof(StateEvent))) {
-                    unknownPropertyFound |= field.FindExtraJsonPropertyFieldsByValueKind(
-                        StateEvent.GetStateEventType(obj.GetProperty("type").GetString()),
-                        mappedProperty.PropertyType);
-                    continue;
-                }
-
-                unknownPropertyFound |=
-                    field.FindExtraJsonPropertyFieldsByValueKind(objectType, mappedProperty.PropertyType);
-                continue;
-            }
-
-            Console.WriteLine($"[!!] Unknown property {field.Name} in {objectType.Name}!");
-            unknownPropertyFound = true;
-        }
-
-        return unknownPropertyFound;
-    }
-
-    private static bool FindExtraJsonPropertyFieldsByValueKind(this JsonProperty field, Type containerType,
-        Type propertyType) {
-        if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) {
-            propertyType = propertyType.GetGenericArguments()[0];
-        }
-
-        bool switchResult = false;
-        switch (field.Value.ValueKind) {
-            case JsonValueKind.Array:
-                switchResult = field.Value.EnumerateArray().Aggregate(switchResult,
-                    (current, element) => current | element.FindExtraJsonElementFields(propertyType, field.Name));
-                break;
-            case JsonValueKind.Object:
-                switchResult |= field.Value.FindExtraJsonElementFields(propertyType, field.Name);
-                break;
-            case JsonValueKind.True:
-            case JsonValueKind.False:
-                return _checkBool(field, containerType, propertyType);
-            case JsonValueKind.String:
-                return _checkString(field, containerType, propertyType);
-            case JsonValueKind.Number:
-                return _checkNumber(field, containerType, propertyType);
-            case JsonValueKind.Undefined:
-            case JsonValueKind.Null:
-                break;
-            default:
-                throw new ArgumentOutOfRangeException();
-        }
-
-        return switchResult;
-    }
-
-    private static bool _checkBool(this JsonProperty field, Type containerType, Type propertyType) {
-        if (propertyType == typeof(bool)) return true;
-        Console.WriteLine(
-            $"[!!] Encountered bool for {field.Name} in {containerType.Name}, the class defines {propertyType.Name}!");
-        return false;
-    }
-
-    private static bool _checkString(this JsonProperty field, Type containerType, Type propertyType) {
-        if (propertyType == typeof(string)) return true;
-        // ReSharper disable once BuiltInTypeReferenceStyle
-        if (propertyType == typeof(String)) return true;
-        Console.WriteLine(
-            $"[!!] Encountered string for {field.Name} in {containerType.Name}, the class defines {propertyType.Name}!");
-        return false;
-    }
-
-    private static bool _checkNumber(this JsonProperty field, Type containerType, Type propertyType) {
-        if (propertyType == typeof(int) ||
-            propertyType == typeof(double) ||
-            propertyType == typeof(float) ||
-            propertyType == typeof(decimal) ||
-            propertyType == typeof(long) ||
-            propertyType == typeof(short) ||
-            propertyType == typeof(uint) ||
-            propertyType == typeof(ulong) ||
-            propertyType == typeof(ushort) ||
-            propertyType == typeof(byte) ||
-            propertyType == typeof(sbyte))
-            return true;
-        Console.WriteLine(
-            $"[!!] Encountered number for {field.Name} in {containerType.Name}, the class defines {propertyType.Name}!");
-        return false;
-    }
-
-    private static bool _checkDictionary(this JsonProperty field, Type containerType, Type propertyType) {
-        var keyType = propertyType.GetGenericArguments()[0];
-        var valueType = propertyType.GetGenericArguments()[1];
-        valueType = Nullable.GetUnderlyingType(valueType) ?? valueType;
-        Console.WriteLine(
-            $"Encountered dictionary {field.Name} with key type {keyType.Name} and value type {valueType.Name}!");
-
-        return field.Value.EnumerateObject()
-            .Where(key => !valueType.IsPrimitive && valueType != typeof(string))
-            .Aggregate(false, (current, key) =>
-                current | key.FindExtraJsonPropertyFieldsByValueKind(containerType, valueType)
-            );
-    }
-
-    private static bool _checkList(this JsonProperty field, Type containerType, Type propertyType) {
-        var valueType = propertyType.GetGenericArguments()[0];
-        valueType = Nullable.GetUnderlyingType(valueType) ?? valueType;
-        Console.WriteLine(
-            $"Encountered list {field.Name} with value type {valueType.Name}!");
-
-        return field.Value.EnumerateArray()
-            .Where(key => !valueType.IsPrimitive && valueType != typeof(string))
-            .Aggregate(false, (current, key) =>
-                current | key.FindExtraJsonElementFields(valueType, field.Name)
-            );
-    }
-}
diff --git a/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs b/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs
deleted file mode 100644
index a4b0791..0000000
--- a/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Text.Encodings.Web;
-using System.Text.Json;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Responses;
-
-namespace MatrixRoomUtils.Core.Extensions;
-
-public static class ObjectExtensions {
-    public static string ToJson(this object obj, bool indent = true, bool ignoreNull = false, bool unsafeContent = false) {
-        var jso = new JsonSerializerOptions();
-        if (indent) jso.WriteIndented = true;
-        if (ignoreNull) jso.IgnoreNullValues = true;
-        if (unsafeContent) jso.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
-        return JsonSerializer.Serialize(obj, jso);
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Extensions/StringExtensions.cs b/MatrixRoomUtils.Core/Extensions/StringExtensions.cs
deleted file mode 100644
index b81d59f..0000000
--- a/MatrixRoomUtils.Core/Extensions/StringExtensions.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace MatrixRoomUtils.Core.Extensions;
-
-public static class StringExtensions {
-    // public static async Task<string> GetMediaUrl(this string MxcUrl)
-    // {
-    //     //MxcUrl: mxc://rory.gay/ocRVanZoUTCcifcVNwXgbtTg
-    //     //target: https://matrix.rory.gay/_matrix/media/v3/download/rory.gay/ocRVanZoUTCcifcVNwXgbtTg
-    //     
-    //     var server = MxcUrl.Split('/')[2];
-    //     var mediaId = MxcUrl.Split('/')[3];
-    //     return $"{(await new RemoteHomeServer(server).Configure()).FullHomeServerDomain}/_matrix/media/v3/download/{server}/{mediaId}";
-    // }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Filters/LocalRoomQueryFilter.cs b/MatrixRoomUtils.Core/Filters/LocalRoomQueryFilter.cs
deleted file mode 100644
index 65c7baa..0000000
--- a/MatrixRoomUtils.Core/Filters/LocalRoomQueryFilter.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace MatrixRoomUtils.Core.Filters;
-
-public class LocalRoomQueryFilter {
-    public string RoomIdContains { get; set; } = "";
-    public string NameContains { get; set; } = "";
-    public string CanonicalAliasContains { get; set; } = "";
-    public string VersionContains { get; set; } = "";
-    public string CreatorContains { get; set; } = "";
-    public string EncryptionContains { get; set; } = "";
-    public string JoinRulesContains { get; set; } = "";
-    public string GuestAccessContains { get; set; } = "";
-    public string HistoryVisibilityContains { get; set; } = "";
-    
-    public bool Federatable { get; set; } = true;
-    public bool Public { get; set; } = true;
-    
-    public int JoinedMembersGreaterThan { get; set; } = 0;
-    public int JoinedMembersLessThan { get; set; } = int.MaxValue;
-
-    public int JoinedLocalMembersGreaterThan { get; set; } = 0;
-    public int JoinedLocalMembersLessThan { get; set; } = int.MaxValue;
-    public int StateEventsGreaterThan { get; set; } = 0;
-    public int StateEventsLessThan { get; set; } = int.MaxValue;
-
-    
-    public bool CheckFederation { get; set; }
-    public bool CheckPublic { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Filters/SyncFilter.cs b/MatrixRoomUtils.Core/Filters/SyncFilter.cs
deleted file mode 100644
index bc81101..0000000
--- a/MatrixRoomUtils.Core/Filters/SyncFilter.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace MatrixRoomUtils.Core.Filters;
-
-public class SyncFilter {
-    [JsonPropertyName("account_data")]
-    public EventFilter? AccountData { get; set; }
-
-    [JsonPropertyName("presence")]
-    public EventFilter? Presence { get; set; }
-
-    [JsonPropertyName("room")]
-    public RoomFilter? Room { get; set; }
-
-    public class RoomFilter {
-        [JsonPropertyName("account_data")]
-        public StateFilter? AccountData { get; set; }
-
-        [JsonPropertyName("ephemeral")]
-        public StateFilter? Ephemeral { get; set; }
-
-        [JsonPropertyName("state")]
-        public StateFilter? State { get; set; }
-
-        [JsonPropertyName("timeline")]
-        public StateFilter? Timeline { get; set; }
-
-
-        public class StateFilter : EventFilter {
-            [JsonPropertyName("contains_url")]
-            public bool? ContainsUrl { get; set; }
-
-            [JsonPropertyName("include_redundant_members")]
-            public bool? IncludeRedundantMembers { get; set; }
-
-            [JsonPropertyName("lazy_load_members")]
-            public bool? LazyLoadMembers { get; set; }
-
-            [JsonPropertyName("rooms")]
-            public List<string>? Rooms { get; set; }
-
-            [JsonPropertyName("not_rooms")]
-            public List<string>? NotRooms { get; set; }
-
-            [JsonPropertyName("unread_thread_notifications")]
-            public bool? UnreadThreadNotifications { get; set; }
-        }
-    }
-
-    public class EventFilter {
-        [JsonPropertyName("limit")]
-        public int? Limit { get; set; }
-
-        [JsonPropertyName("types")]
-        public List<string>? Types { get; set; }
-
-        [JsonPropertyName("not_types")]
-        public List<string>? NotTypes { get; set; }
-
-        [JsonPropertyName("senders")]
-        public List<string>? Senders { get; set; }
-
-        [JsonPropertyName("not_senders")]
-        public List<string>? NotSenders { get; set; }
-    }
-}
diff --git a/MatrixRoomUtils.Core/Helpers/MediaResolver.cs b/MatrixRoomUtils.Core/Helpers/MediaResolver.cs
deleted file mode 100644
index 0869135..0000000
--- a/MatrixRoomUtils.Core/Helpers/MediaResolver.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace MatrixRoomUtils.Core.Helpers; 
-
-public class MediaResolver {
-    public static string ResolveMediaUri(string homeserver, string mxc) => 
-        mxc.Replace("mxc://", $"{homeserver}/_matrix/media/v3/download/");
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Helpers/SyncHelper.cs b/MatrixRoomUtils.Core/Helpers/SyncHelper.cs
deleted file mode 100644
index e12164c..0000000
--- a/MatrixRoomUtils.Core/Helpers/SyncHelper.cs
+++ /dev/null
@@ -1,238 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using System.Net.Http.Json;
-using System.Text.Json;
-using System.Text.Json.Nodes;
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Filters;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.Responses.Admin;
-using MatrixRoomUtils.Core.Services;
-using MatrixRoomUtils.Core.StateEventTypes;
-
-namespace MatrixRoomUtils.Core.Helpers;
-
-public class SyncHelper {
-    private readonly AuthenticatedHomeServer _homeServer;
-    private readonly TieredStorageService _storageService;
-
-    public SyncHelper(AuthenticatedHomeServer homeServer, TieredStorageService storageService) {
-        _homeServer = homeServer;
-        _storageService = storageService;
-    }
-
-    public async Task<SyncResult?> Sync(
-        string? since = null,
-        int? timeout = 30000,
-        string? setPresence = "online",
-        SyncFilter? filter = null,
-        CancellationToken? cancellationToken = null) {
-        var outFileName = "sync-" +
-                          (await _storageService.CacheStorageProvider.GetAllKeysAsync()).Count(
-                              x => x.StartsWith("sync")) +
-                          ".json";
-        var url = $"/_matrix/client/v3/sync?timeout={timeout}&set_presence={setPresence}";
-        if (!string.IsNullOrWhiteSpace(since)) url += $"&since={since}";
-        if (filter is not null) url += $"&filter={filter.ToJson(ignoreNull: true, indent: false)}";
-        // else url += "&full_state=true";
-        Console.WriteLine("Calling: " + url);
-        try {
-            var req = await _homeServer._httpClient.GetAsync(url, cancellationToken: cancellationToken ?? CancellationToken.None);
-
-            // var res = await JsonSerializer.DeserializeAsync<SyncResult>(await req.Content.ReadAsStreamAsync());
-
-#if DEBUG && false
-            var jsonObj = await req.Content.ReadFromJsonAsync<JsonElement>();
-            try {
-                await _homeServer._httpClient.PostAsJsonAsync(
-                    "http://localhost:5116/validate/" + typeof(SyncResult).AssemblyQualifiedName, jsonObj);
-            }
-            catch (Exception e) {
-                Console.WriteLine("[!!] Checking sync response failed: " + e);
-            }
-
-            var res = jsonObj.Deserialize<SyncResult>();
-            return res;
-#else
-            return await req.Content.ReadFromJsonAsync<SyncResult>();
-#endif
-        }
-        catch (TaskCanceledException) {
-            Console.WriteLine("Sync cancelled!");
-        }
-        catch (Exception e) {
-            Console.WriteLine(e);
-        }
-
-        return null;
-    }
-
-    [SuppressMessage("ReSharper", "FunctionNeverReturns")]
-    public async Task RunSyncLoop(
-        bool skipInitialSyncEvents = true,
-        string? since = null,
-        int? timeout = 30000,
-        string? setPresence = "online",
-        SyncFilter? filter = null,
-        CancellationToken? cancellationToken = null
-    ) {
-        await Task.WhenAll((await _storageService.CacheStorageProvider.GetAllKeysAsync())
-            .Where(x => x.StartsWith("sync"))
-            .ToList()
-            .Select(x => _storageService.CacheStorageProvider.DeleteObjectAsync(x)));
-        SyncResult? sync = null;
-        string? nextBatch = since;
-        while (cancellationToken is null || !cancellationToken.Value.IsCancellationRequested) {
-            sync = await Sync(since: nextBatch, timeout: timeout, setPresence: setPresence, filter: filter,
-                cancellationToken: cancellationToken);
-            nextBatch = sync?.NextBatch ?? nextBatch;
-            if (sync is null) continue;
-            Console.WriteLine($"Got sync, next batch: {nextBatch}!");
-
-            if (sync.Rooms is { Invite.Count: > 0 }) {
-                foreach (var roomInvite in sync.Rooms.Invite) {
-                    var tasks = InviteReceivedHandlers.Select(x => x(roomInvite)).ToList();
-                    await Task.WhenAll(tasks);
-                }
-            }
-
-            if (sync.AccountData is { Events: { Count: > 0 } }) {
-                foreach (var accountDataEvent in sync.AccountData.Events) {
-                    var tasks = AccountDataReceivedHandlers.Select(x => x(accountDataEvent)).ToList();
-                    await Task.WhenAll(tasks);
-                }
-            }
-
-            // Things that are skipped on the first sync
-            if (skipInitialSyncEvents) {
-                skipInitialSyncEvents = false;
-                continue;
-            }
-
-            if (sync.Rooms is { Join.Count: > 0 }) {
-                foreach (var updatedRoom in sync.Rooms.Join) {
-                    foreach (var stateEventResponse in updatedRoom.Value.Timeline.Events) {
-                        stateEventResponse.RoomId = updatedRoom.Key;
-                        var tasks = TimelineEventHandlers.Select(x => x(stateEventResponse)).ToList();
-                        await Task.WhenAll(tasks);
-                    }
-                }
-            }
-        }
-    }
-
-    /// <summary>
-    /// Event fired when a room invite is received
-    /// </summary>
-    public List<Func<KeyValuePair<string, SyncResult.RoomsDataStructure.InvitedRoomDataStructure>, Task>>
-        InviteReceivedHandlers { get; } = new();
-
-    public List<Func<StateEventResponse, Task>> TimelineEventHandlers { get; } = new();
-    public List<Func<StateEventResponse, Task>> AccountDataReceivedHandlers { get; } = new();
-}
-
-public class SyncResult {
-    [JsonPropertyName("next_batch")]
-    public string NextBatch { get; set; }
-
-    [JsonPropertyName("account_data")]
-    public EventList? AccountData { get; set; }
-
-    [JsonPropertyName("presence")]
-    public PresenceDataStructure? Presence { get; set; }
-
-    [JsonPropertyName("device_one_time_keys_count")]
-    public Dictionary<string, int> DeviceOneTimeKeysCount { get; set; }
-
-    [JsonPropertyName("rooms")]
-    public RoomsDataStructure? Rooms { get; set; }
-
-    [JsonPropertyName("to_device")]
-    public EventList? ToDevice { get; set; }
-
-    [JsonPropertyName("device_lists")]
-    public DeviceListsDataStructure? DeviceLists { get; set; }
-
-    public class DeviceListsDataStructure {
-        [JsonPropertyName("changed")]
-        public List<string>? Changed { get; set; }
-
-        [JsonPropertyName("left")]
-        public List<string>? Left { get; set; }
-    }
-
-    // supporting classes
-    public class PresenceDataStructure {
-        [JsonPropertyName("events")]
-        public List<StateEventResponse> Events { get; set; }
-    }
-
-    public class RoomsDataStructure {
-        [JsonPropertyName("join")]
-        public Dictionary<string, JoinedRoomDataStructure>? Join { get; set; }
-
-        [JsonPropertyName("invite")]
-        public Dictionary<string, InvitedRoomDataStructure>? Invite { get; set; }
-
-        public class JoinedRoomDataStructure {
-            [JsonPropertyName("timeline")]
-            public TimelineDataStructure Timeline { get; set; }
-
-            [JsonPropertyName("state")]
-            public EventList State { get; set; }
-
-            [JsonPropertyName("account_data")]
-            public EventList AccountData { get; set; }
-
-            [JsonPropertyName("ephemeral")]
-            public EventList Ephemeral { get; set; }
-
-            [JsonPropertyName("unread_notifications")]
-            public UnreadNotificationsDataStructure UnreadNotifications { get; set; }
-
-            [JsonPropertyName("summary")]
-            public SummaryDataStructure Summary { get; set; }
-
-            public class TimelineDataStructure {
-                [JsonPropertyName("events")]
-                public List<StateEventResponse> Events { get; set; }
-
-                [JsonPropertyName("prev_batch")]
-                public string PrevBatch { get; set; }
-
-                [JsonPropertyName("limited")]
-                public bool Limited { get; set; }
-            }
-
-            public class UnreadNotificationsDataStructure {
-                [JsonPropertyName("notification_count")]
-                public int NotificationCount { get; set; }
-
-                [JsonPropertyName("highlight_count")]
-                public int HighlightCount { get; set; }
-            }
-
-            public class SummaryDataStructure {
-                [JsonPropertyName("m.heroes")]
-                public List<string> Heroes { get; set; }
-
-                [JsonPropertyName("m.invited_member_count")]
-                public int InvitedMemberCount { get; set; }
-
-                [JsonPropertyName("m.joined_member_count")]
-                public int JoinedMemberCount { get; set; }
-            }
-        }
-
-        public class InvitedRoomDataStructure {
-            [JsonPropertyName("invite_state")]
-            public EventList InviteState { get; set; }
-        }
-    }
-}
-
-public class EventList {
-    [JsonPropertyName("events")]
-    public List<StateEventResponse> Events { get; set; }
-}
diff --git a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
deleted file mode 100644
index 3521a51..0000000
--- a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Net.Http.Json;
-using System.Text.Json;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.StateEventTypes;
-using MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-namespace MatrixRoomUtils.Core.Interfaces;
-
-public class IHomeServer {
-    private readonly Dictionary<string, object> _profileCache = new();
-    public string HomeServerDomain { get; set; }
-    public string FullHomeServerDomain { get; set; }
-
-    public MatrixHttpClient _httpClient { get; set; } = new();
-
-    public async Task<ProfileResponseEventData> GetProfile(string mxid) {
-        if(mxid is null) throw new ArgumentNullException(nameof(mxid));
-        if (_profileCache.ContainsKey(mxid)) {
-            if (_profileCache[mxid] is SemaphoreSlim s) await s.WaitAsync();
-            if (_profileCache[mxid] is ProfileResponseEventData p) return p;
-        }
-        _profileCache[mxid] = new SemaphoreSlim(1);
-
-        var resp = await _httpClient.GetAsync($"/_matrix/client/v3/profile/{mxid}");
-        var data = await resp.Content.ReadFromJsonAsync<ProfileResponseEventData>();
-        if (!resp.IsSuccessStatusCode) Console.WriteLine("Profile: " + data);
-        _profileCache[mxid] = data;
-
-        return data;
-    }
-}
diff --git a/MatrixRoomUtils.Core/Interfaces/IStateEventType.cs b/MatrixRoomUtils.Core/Interfaces/IStateEventType.cs
deleted file mode 100644
index 053f50c..0000000
--- a/MatrixRoomUtils.Core/Interfaces/IStateEventType.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace MatrixRoomUtils.Core.Interfaces; 
-
-public interface IStateEventType {
-    
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Interfaces/Services/IStorageProvider.cs b/MatrixRoomUtils.Core/Interfaces/Services/IStorageProvider.cs
deleted file mode 100644
index 1de9885..0000000
--- a/MatrixRoomUtils.Core/Interfaces/Services/IStorageProvider.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-namespace MatrixRoomUtils.Core.Interfaces.Services;
-
-public interface IStorageProvider {
-    // save all children of a type with reflection
-    public Task SaveAllChildrenAsync<T>(string key, T value) {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement SaveAllChildren<T>(key, value)!");
-        throw new NotImplementedException();
-    }
-
-    // load all children of a type with reflection
-    public Task<T?> LoadAllChildrenAsync<T>(string key) {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement LoadAllChildren<T>(key)!");
-        throw new NotImplementedException();
-    }
-
-
-    public Task SaveObjectAsync<T>(string key, T value) {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement SaveObject<T>(key, value)!");
-        throw new NotImplementedException();
-    }
-
-    // load
-    public Task<T?> LoadObjectAsync<T>(string key) {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement LoadObject<T>(key)!");
-        throw new NotImplementedException();
-    }
-
-    // check if exists
-    public Task<bool> ObjectExistsAsync(string key) {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement ObjectExists(key)!");
-        throw new NotImplementedException();
-    }
-
-    // get all keys
-    public Task<List<string>> GetAllKeysAsync() {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement GetAllKeys()!");
-        throw new NotImplementedException();
-    }
-
-
-    // delete
-    public Task DeleteObjectAsync(string key) {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement DeleteObject(key)!");
-        throw new NotImplementedException();
-    }
-
-    // save stream
-    public Task SaveStreamAsync(string key, Stream stream) {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement SaveStream(key, stream)!");
-        throw new NotImplementedException();
-    }
-
-    // load stream
-    public Task<Stream?> LoadStreamAsync(string key) {
-        Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement LoadStream(key)!");
-        throw new NotImplementedException();
-    }
-}
diff --git a/MatrixRoomUtils.Core/MatrixException.cs b/MatrixRoomUtils.Core/MatrixException.cs
deleted file mode 100644
index a469a62..0000000
--- a/MatrixRoomUtils.Core/MatrixException.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-
-namespace MatrixRoomUtils.Core;
-
-public class MatrixException : Exception {
-    [JsonPropertyName("errcode")]
-    public string ErrorCode { get; set; }
-
-    [JsonPropertyName("error")]
-    public string Error { get; set; }
-
-    [JsonPropertyName("soft_logout")]
-    public bool? SoftLogout { get; set; }
-
-    [JsonPropertyName("retry_after_ms")]
-    public int? RetryAfterMs { get; set; }
-
-    public string RawContent { get; set; }
-
-    public override string Message =>
-        $"{ErrorCode}: {ErrorCode switch {
-            // common
-            "M_FORBIDDEN" => $"You do not have permission to perform this action: {Error}",
-            "M_UNKNOWN_TOKEN" => $"The access token specified was not recognised: {Error}{(SoftLogout == true ? " (soft logout)" : "")}",
-            "M_MISSING_TOKEN" => $"No access token was specified: {Error}",
-            "M_BAD_JSON" => $"Request contained valid JSON, but it was malformed in some way: {Error}",
-            "M_NOT_JSON" => $"Request did not contain valid JSON: {Error}",
-            "M_NOT_FOUND" => $"The requested resource was not found: {Error}",
-            "M_LIMIT_EXCEEDED" => $"Too many requests have been sent in a short period of time. Wait a while then try again: {Error}",
-            "M_UNRECOGNISED" => $"The server did not recognise the request: {Error}",
-            "M_UNKOWN" => $"The server encountered an unexpected error: {Error}",
-            // endpoint specific
-            "M_UNAUTHORIZED" => $"The request did not contain valid authentication information for the target of the request: {Error}",
-            "M_USER_DEACTIVATED" => $"The user ID associated with the request has been deactivated: {Error}",
-            "M_USER_IN_USE" => $"The user ID associated with the request is already in use: {Error}",
-            "M_INVALID_USERNAME" => $"The requested user ID is not valid: {Error}",
-            "M_ROOM_IN_USE" => $"The room alias requested is already taken: {Error}",
-            "M_INVALID_ROOM_STATE" => $"The room associated with the request is not in a valid state to perform the request: {Error}",
-            "M_THREEPID_IN_USE" => $"The threepid requested is already associated with a user ID on this server: {Error}",
-            "M_THREEPID_NOT_FOUND" => $"The threepid requested is not associated with any user ID: {Error}",
-            "M_THREEPID_AUTH_FAILED" => $"The provided threepid and/or token was invalid: {Error}",
-            "M_THREEPID_DENIED" => $"The homeserver does not permit the third party identifier in question: {Error}",
-            "M_SERVER_NOT_TRUSTED" => $"The homeserver does not trust the identity server: {Error}",
-            "M_UNSUPPORTED_ROOM_VERSION" => $"The room version is not supported: {Error}",
-            "M_INCOMPATIBLE_ROOM_VERSION" => $"The room version is incompatible: {Error}",
-            "M_BAD_STATE" => $"The request was invalid because the state was invalid: {Error}",
-            "M_GUEST_ACCESS_FORBIDDEN" => $"Guest access is forbidden: {Error}",
-            "M_CAPTCHA_NEEDED" => $"Captcha needed: {Error}",
-            "M_CAPTCHA_INVALID" => $"Captcha invalid: {Error}",
-            "M_MISSING_PARAM" => $"Missing parameter: {Error}",
-            "M_INVALID_PARAM" => $"Invalid parameter: {Error}",
-            "M_TOO_LARGE" => $"The request or entity was too large: {Error}",
-            "M_EXCLUSIVE" => $"The resource being requested is reserved by an application service, or the application service making the request has not created the resource: {Error}",
-            "M_RESOURCE_LIMIT_EXCEEDED" => $"Exceeded resource limit: {Error}",
-            "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM" => $"Cannot leave server notice room: {Error}",
-            _ => $"Unknown error: {new { ErrorCode, Error, SoftLogout, RetryAfterMs }.ToJson(ignoreNull: true)}"
-        }}";
-}
diff --git a/MatrixRoomUtils.Core/MatrixRoomUtils.Core.csproj b/MatrixRoomUtils.Core/MatrixRoomUtils.Core.csproj
deleted file mode 100644
index 3571eab..0000000
--- a/MatrixRoomUtils.Core/MatrixRoomUtils.Core.csproj
+++ /dev/null
@@ -1,14 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
-    <PropertyGroup>
-        <TargetFramework>net7.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
-    </PropertyGroup>
-
-    <ItemGroup>
-        <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
-        <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
-    </ItemGroup>
-
-</Project>
diff --git a/MatrixRoomUtils.Core/MessagesResponse.cs b/MatrixRoomUtils.Core/MessagesResponse.cs
deleted file mode 100644
index 7a303bc..0000000
--- a/MatrixRoomUtils.Core/MessagesResponse.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Responses;
-
-namespace MatrixRoomUtils.Core;
-
-public class MessagesResponse {
-    [JsonPropertyName("start")]
-    public string Start { get; set; }
-
-    [JsonPropertyName("end")]
-    public string? End { get; set; }
-
-    [JsonPropertyName("chunk")]
-    public List<StateEventResponse> Chunk { get; set; } = new();
-
-    [JsonPropertyName("state")]
-    public List<StateEventResponse> State { get; set; } = new();
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/RemoteHomeServer.cs b/MatrixRoomUtils.Core/RemoteHomeServer.cs
deleted file mode 100644
index e6c28c3..0000000
--- a/MatrixRoomUtils.Core/RemoteHomeServer.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Net.Http.Json;
-using System.Text.Json;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Services;
-
-namespace MatrixRoomUtils.Core;
-
-public class RemoteHomeServer : IHomeServer {
-    public RemoteHomeServer(string canonicalHomeServerDomain) {
-        HomeServerDomain = canonicalHomeServerDomain;
-        _httpClient = new MatrixHttpClient();
-        _httpClient.Timeout = TimeSpan.FromSeconds(5);
-    }
-
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Responses/Admin/AdminRoomDeleteRequest.cs b/MatrixRoomUtils.Core/Responses/Admin/AdminRoomDeleteRequest.cs
deleted file mode 100644
index 5605329..0000000
--- a/MatrixRoomUtils.Core/Responses/Admin/AdminRoomDeleteRequest.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace MatrixRoomUtils.Core.Responses.Admin; 
-
-public class AdminRoomDeleteRequest {
-    [JsonPropertyName("new_room_user_id")]
-    public string? NewRoomUserId { get; set; }
-    [JsonPropertyName("room_name")]
-    public string? RoomName { get; set; }
-    [JsonPropertyName("block")]
-    public bool Block { get; set; }
-    [JsonPropertyName("purge")]
-    public bool Purge { get; set; }
-    [JsonPropertyName("message")]
-    public string? Message { get; set; }
-    [JsonPropertyName("force_purge")]
-    public bool ForcePurge { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Responses/Admin/AdminRoomListingResult.cs b/MatrixRoomUtils.Core/Responses/Admin/AdminRoomListingResult.cs
deleted file mode 100644
index d6da859..0000000
--- a/MatrixRoomUtils.Core/Responses/Admin/AdminRoomListingResult.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace MatrixRoomUtils.Core.Responses.Admin;
-
-public class AdminRoomListingResult {
-    [JsonPropertyName("offset")]
-    public int Offset { get; set; }
-
-    [JsonPropertyName("total_rooms")]
-    public int TotalRooms { get; set; }
-
-    [JsonPropertyName("next_batch")]
-    public int? NextBatch { get; set; }
-
-    [JsonPropertyName("prev_batch")]
-    public int? PrevBatch { get; set; }
-
-    [JsonPropertyName("rooms")]
-    public List<AdminRoomListingResultRoom> Rooms { get; set; } = new();
-
-    public class AdminRoomListingResultRoom {
-        [JsonPropertyName("room_id")]
-        public string RoomId { get; set; }
-
-        [JsonPropertyName("name")]
-        public string? Name { get; set; }
-
-        [JsonPropertyName("canonical_alias")]
-        public string? CanonicalAlias { get; set; }
-
-        [JsonPropertyName("joined_members")]
-        public int JoinedMembers { get; set; }
-
-        [JsonPropertyName("joined_local_members")]
-        public int JoinedLocalMembers { get; set; }
-
-        [JsonPropertyName("version")]
-        public string Version { get; set; }
-
-        [JsonPropertyName("creator")]
-        public string Creator { get; set; }
-
-        [JsonPropertyName("encryption")]
-        public string? Encryption { get; set; }
-
-        [JsonPropertyName("federatable")]
-        public bool Federatable { get; set; }
-
-        [JsonPropertyName("public")]
-        public bool Public { get; set; }
-
-        [JsonPropertyName("join_rules")]
-        public string? JoinRules { get; set; }
-
-        [JsonPropertyName("guest_access")]
-        public string? GuestAccess { get; set; }
-
-        [JsonPropertyName("history_visibility")]
-        public string? HistoryVisibility { get; set; }
-
-        [JsonPropertyName("state_events")]
-        public int StateEvents { get; set; }
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs b/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs
deleted file mode 100644
index 540a323..0000000
--- a/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System.Reflection;
-using System.Text.Json.Nodes;
-using System.Text.Json.Serialization;
-using System.Text.RegularExpressions;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.StateEventTypes;
-using MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-namespace MatrixRoomUtils.Core.Responses;
-
-public class CreateRoomRequest {
-    [JsonIgnore] public CreationContentBaseType _creationContentBaseType;
-
-    public CreateRoomRequest() => _creationContentBaseType = new CreationContentBaseType(this);
-
-    [JsonPropertyName("name")]
-    public string Name { get; set; } = null!;
-
-    [JsonPropertyName("room_alias_name")]
-    public string RoomAliasName { get; set; } = null!;
-
-    //we dont want to use this, we want more control
-    // [JsonPropertyName("preset")]
-    // public string Preset { get; set; } = null!;
-
-    [JsonPropertyName("initial_state")]
-    public List<StateEvent> InitialState { get; set; } = null!;
-
-    [JsonPropertyName("visibility")]
-    public string Visibility { get; set; } = null!;
-
-    [JsonPropertyName("power_level_content_override")]
-    public RoomPowerLevelEventData PowerLevelContentOverride { get; set; } = null!;
-
-    [JsonPropertyName("creation_content")]
-    public JsonObject CreationContent { get; set; } = new();
-
-    /// <summary>
-    ///     For use only when you can't use the CreationContent property
-    /// </summary>
-
-    public StateEvent this[string event_type, string event_key = ""] {
-        get {
-            var stateEvent = InitialState.FirstOrDefault(x => x.Type == event_type && x.StateKey == event_key);
-            if (stateEvent == null) {
-                InitialState.Add(stateEvent = new StateEvent {
-                    Type = event_type,
-                    StateKey = event_key,
-                    TypedContent = Activator.CreateInstance(
-                        StateEvent.KnownStateEventTypes.FirstOrDefault(x =>
-                            x.GetCustomAttributes<MatrixEventAttribute>()?
-                                .Any(y => y.EventName == event_type) ?? false) ?? typeof(object)
-                        )
-                });
-            }
-            return stateEvent;
-        }
-        set {
-            var stateEvent = InitialState.FirstOrDefault(x => x.Type == event_type && x.StateKey == event_key);
-            if (stateEvent == null)
-                InitialState.Add(value);
-            else
-                InitialState[InitialState.IndexOf(stateEvent)] = value;
-        }
-    }
-
-    public Dictionary<string, string> Validate() {
-        Dictionary<string, string> errors = new();
-        if (!Regex.IsMatch(RoomAliasName, @"[a-zA-Z0-9_\-]+$"))
-            errors.Add("room_alias_name",
-                "Room alias name must only contain letters, numbers, underscores, and hyphens.");
-
-        return errors;
-    }
-}
diff --git a/MatrixRoomUtils.Core/Responses/CreationContentBaseType.cs b/MatrixRoomUtils.Core/Responses/CreationContentBaseType.cs
deleted file mode 100644
index 743c552..0000000
--- a/MatrixRoomUtils.Core/Responses/CreationContentBaseType.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace MatrixRoomUtils.Core.Responses;
-
-public class CreationContentBaseType {
-    private readonly CreateRoomRequest createRoomRequest;
-
-    public CreationContentBaseType(CreateRoomRequest createRoomRequest) => this.createRoomRequest = createRoomRequest;
-
-    [JsonPropertyName("type")]
-    public string Type {
-        get => (string)createRoomRequest.CreationContent["type"];
-        set {
-            if (value is "null" or "") createRoomRequest.CreationContent.Remove("type");
-            else createRoomRequest.CreationContent["type"] = value;
-        }
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Responses/LoginResponse.cs b/MatrixRoomUtils.Core/Responses/LoginResponse.cs
deleted file mode 100644
index 239ea03..0000000
--- a/MatrixRoomUtils.Core/Responses/LoginResponse.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace MatrixRoomUtils.Core.Responses;
-
-public class LoginResponse {
-    [JsonPropertyName("access_token")]
-    public string AccessToken { get; set; }
-
-    [JsonPropertyName("device_id")]
-    public string DeviceId { get; set; }
-
-    [JsonPropertyName("home_server")]
-    public string Homeserver { get; set; }
-
-    [JsonPropertyName("user_id")]
-    public string UserId { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Responses/StateEventResponse.cs b/MatrixRoomUtils.Core/Responses/StateEventResponse.cs
deleted file mode 100644
index a7f9187..0000000
--- a/MatrixRoomUtils.Core/Responses/StateEventResponse.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System.Text.Json.Nodes;
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.Responses;
-
-public class StateEventResponse : StateEvent {
-    [JsonPropertyName("origin_server_ts")]
-    public ulong OriginServerTs { get; set; }
-
-    [JsonPropertyName("room_id")]
-    public string RoomId { get; set; }
-
-    [JsonPropertyName("sender")]
-    public string Sender { get; set; }
-
-    [JsonPropertyName("unsigned")]
-    public UnsignedData? Unsigned { get; set; }
-
-    [JsonPropertyName("event_id")]
-    public string EventId { get; set; }
-
-    [JsonPropertyName("user_id")]
-    public string UserId { get; set; }
-
-    [JsonPropertyName("replaces_state")]
-    public string ReplacesState { get; set; }
-
-    public class UnsignedData {
-        [JsonPropertyName("age")]
-        public ulong? Age { get; set; }
-
-        [JsonPropertyName("redacted_because")]
-        public object? RedactedBecause { get; set; }
-
-        [JsonPropertyName("transaction_id")]
-        public string? TransactionId { get; set; }
-
-        [JsonPropertyName("replaces_state")]
-        public string? ReplacesState { get; set; }
-
-        [JsonPropertyName("prev_sender")]
-        public string? PrevSender { get; set; }
-
-        [JsonPropertyName("prev_content")]
-        public JsonObject? PrevContent { get; set; }
-    }
-}
diff --git a/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs b/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs
deleted file mode 100644
index eced379..0000000
--- a/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs
+++ /dev/null
@@ -1,187 +0,0 @@
-using System.Net.Http.Json;
-using System.Text.Json;
-using System.Text.Json.Nodes;
-using System.Web;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-namespace MatrixRoomUtils.Core.RoomTypes;
-
-public class GenericRoom {
-    internal readonly AuthenticatedHomeServer _homeServer;
-    internal readonly MatrixHttpClient _httpClient;
-
-    public GenericRoom(AuthenticatedHomeServer homeServer, string roomId) {
-        _homeServer = homeServer;
-        _httpClient = homeServer._httpClient;
-        RoomId = roomId;
-        if (GetType() != typeof(SpaceRoom))
-            AsSpace = new SpaceRoom(homeServer, RoomId);
-    }
-
-    public string RoomId { get; set; }
-
-    [Obsolete("", true)]
-    public async Task<JsonElement?> GetStateAsync(string type, string stateKey = "") {
-        var url = $"/_matrix/client/v3/rooms/{RoomId}/state";
-        if (!string.IsNullOrEmpty(type)) url += $"/{type}";
-        if (!string.IsNullOrEmpty(stateKey)) url += $"/{stateKey}";
-        return await _httpClient.GetFromJsonAsync<JsonElement>(url);
-    }
-
-    public async IAsyncEnumerable<StateEventResponse?> GetFullStateAsync() {
-        var res = await _httpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/state");
-        var result =
-            JsonSerializer.DeserializeAsyncEnumerable<StateEventResponse>(await res.Content.ReadAsStreamAsync());
-        await foreach (var resp in result) {
-            yield return resp;
-        }
-    }
-
-    public async Task<T?> GetStateAsync<T>(string type, string stateKey = "") {
-        var url = $"/_matrix/client/v3/rooms/{RoomId}/state";
-        if (!string.IsNullOrEmpty(type)) url += $"/{type}";
-        if (!string.IsNullOrEmpty(stateKey)) url += $"/{stateKey}";
-        try {
-#if DEBUG && false
-            var resp = await _httpClient.GetFromJsonAsync<JsonObject>(url);
-            try {
-                _homeServer._httpClient.PostAsJsonAsync(
-                    "http://localhost:5116/validate/" + typeof(T).AssemblyQualifiedName, resp);
-            }
-            catch (Exception e) {
-                Console.WriteLine("[!!] Checking state response failed: " + e);
-            }
-
-            return resp.Deserialize<T>();
-#else
-            var resp = await _httpClient.GetFromJsonAsync<T>(url);
-            return resp;
-#endif
-        }
-        catch (MatrixException e) {
-            if (e is not { ErrorCode: "M_NOT_FOUND" }) {
-                throw;
-            }
-
-            Console.WriteLine(e);
-            return default;
-        }
-    }
-
-    public async Task<MessagesResponse> GetMessagesAsync(string from = "", int limit = 10, string dir = "b",
-        string filter = "") {
-        var url = $"/_matrix/client/v3/rooms/{RoomId}/messages?from={from}&limit={limit}&dir={dir}";
-        if (!string.IsNullOrEmpty(filter)) url += $"&filter={filter}";
-        var res = await _httpClient.GetFromJsonAsync<MessagesResponse>(url);
-        return res ?? new MessagesResponse();
-    }
-
-    public async Task<string> GetNameAsync() {
-        try {
-            var res = await GetStateAsync<RoomNameEventData>("m.room.name");
-            return res?.Name ?? RoomId;
-        }
-        catch (MatrixException e) {
-            return $"{RoomId} ({e.ErrorCode})";
-        }
-    }
-
-    public async Task JoinAsync(string[]? homeservers = null, string? reason = null) {
-        var join_url = $"/_matrix/client/v3/join/{HttpUtility.UrlEncode(RoomId)}";
-        Console.WriteLine($"Calling {join_url} with {homeservers?.Length ?? 0} via's...");
-        if (homeservers == null || homeservers.Length == 0) homeservers = new[] { RoomId.Split(':')[1] };
-        var fullJoinUrl = $"{join_url}?server_name=" + string.Join("&server_name=", homeservers);
-        var res = await _httpClient.PostAsJsonAsync(fullJoinUrl, new {
-            reason
-        });
-    }
-
-    public async IAsyncEnumerable<StateEventResponse> GetMembersAsync(bool joinedOnly = true) {
-        var res = GetFullStateAsync();
-        await foreach (var member in res) {
-            if (member.Type != "m.room.member") continue;
-            if (joinedOnly && (member.TypedContent as RoomMemberEventData).Membership is not "join") continue;
-            yield return member;
-        }
-    }
-
-    public async Task<List<string>> GetAliasesAsync() {
-        var res = await GetStateAsync<RoomAliasEventData>("m.room.aliases");
-        return res.Aliases;
-    }
-
-    public async Task<CanonicalAliasEventData?> GetCanonicalAliasAsync() =>
-        await GetStateAsync<CanonicalAliasEventData>("m.room.canonical_alias");
-
-    public async Task<RoomTopicEventData?> GetTopicAsync() =>
-        await GetStateAsync<RoomTopicEventData>("m.room.topic");
-
-    public async Task<RoomAvatarEventData?> GetAvatarUrlAsync() =>
-        await GetStateAsync<RoomAvatarEventData>("m.room.avatar");
-
-    public async Task<JoinRulesEventData> GetJoinRuleAsync() =>
-        await GetStateAsync<JoinRulesEventData>("m.room.join_rules");
-
-    public async Task<HistoryVisibilityEventData?> GetHistoryVisibilityAsync() =>
-        await GetStateAsync<HistoryVisibilityEventData>("m.room.history_visibility");
-
-    public async Task<GuestAccessEventData?> GetGuestAccessAsync() =>
-        await GetStateAsync<GuestAccessEventData>("m.room.guest_access");
-
-    public async Task<RoomCreateEventData> GetCreateEventAsync() =>
-        await GetStateAsync<RoomCreateEventData>("m.room.create");
-
-    public async Task<string?> GetRoomType() {
-        var res = await GetStateAsync<RoomCreateEventData>("m.room.create");
-        return res.Type;
-    }
-
-    public async Task ForgetAsync() =>
-        await _httpClient.PostAsync($"/_matrix/client/v3/rooms/{RoomId}/forget", null);
-
-    public async Task LeaveAsync(string? reason = null) =>
-        await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/leave", new {
-            reason
-        });
-
-    public async Task KickAsync(string userId, string? reason = null) =>
-        await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/kick",
-            new UserIdAndReason() { UserId = userId, Reason = reason });
-
-    public async Task BanAsync(string userId, string? reason = null) =>
-        await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/ban",
-            new UserIdAndReason() { UserId = userId, Reason = reason });
-
-    public async Task UnbanAsync(string userId) =>
-        await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/unban",
-            new UserIdAndReason() { UserId = userId });
-
-    public async Task<EventIdResponse> SendStateEventAsync(string eventType, object content) =>
-        await (await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/state/{eventType}", content))
-            .Content.ReadFromJsonAsync<EventIdResponse>();
-
-    public async Task<EventIdResponse> SendMessageEventAsync(string eventType, RoomMessageEventData content) {
-        var res = await _httpClient.PutAsJsonAsync(
-            $"/_matrix/client/v3/rooms/{RoomId}/send/{eventType}/" + Guid.NewGuid(), content);
-        var resu = await res.Content.ReadFromJsonAsync<EventIdResponse>();
-        return resu;
-    }
-
-    public async Task<EventIdResponse> SendFileAsync(string eventType, string fileName, Stream fileStream) {
-        var content = new MultipartFormDataContent();
-        content.Add(new StreamContent(fileStream), "file", fileName);
-        var res = await
-            (
-                await _httpClient.PutAsync(
-                    $"/_matrix/client/v3/rooms/{RoomId}/send/{eventType}/" + Guid.NewGuid(),
-                    content
-                )
-            )
-            .Content.ReadFromJsonAsync<EventIdResponse>();
-        return res;
-    }
-
-    public readonly SpaceRoom AsSpace;
-}
diff --git a/MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs b/MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs
deleted file mode 100644
index 1b93064..0000000
--- a/MatrixRoomUtils.Core/RoomTypes/SpaceRoom.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Text.Json;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Responses;
-
-namespace MatrixRoomUtils.Core.RoomTypes;
-
-public class SpaceRoom : GenericRoom {
-    private readonly AuthenticatedHomeServer _homeServer;
-    private readonly GenericRoom _room;
-
-    public SpaceRoom(AuthenticatedHomeServer homeServer, string roomId) : base(homeServer, roomId) {
-        _homeServer = homeServer;
-    }
-
-    private static SemaphoreSlim _semaphore = new(1, 1);
-    public async IAsyncEnumerable<GenericRoom> GetRoomsAsync(bool includeRemoved = false) {
-        await _semaphore.WaitAsync();
-        var rooms = new List<GenericRoom>();
-        var state = GetFullStateAsync();
-        await foreach (var stateEvent in state) {
-            if (stateEvent.Type != "m.space.child") continue;
-            if (stateEvent.RawContent.ToJson() != "{}" || includeRemoved)
-                yield return await _homeServer.GetRoom(stateEvent.StateKey);
-        }
-        _semaphore.Release();
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Services/HomeserverProviderService.cs b/MatrixRoomUtils.Core/Services/HomeserverProviderService.cs
deleted file mode 100644
index 4bc785a..0000000
--- a/MatrixRoomUtils.Core/Services/HomeserverProviderService.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using System.Net.Http.Headers;
-using System.Net.Http.Json;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Responses;
-using Microsoft.Extensions.Logging;
-
-namespace MatrixRoomUtils.Core.Services;
-
-public class HomeserverProviderService {
-    private readonly TieredStorageService _tieredStorageService;
-    private readonly ILogger<HomeserverProviderService> _logger;
-    private readonly HomeserverResolverService _homeserverResolverService;
-
-    public HomeserverProviderService(TieredStorageService tieredStorageService,
-        ILogger<HomeserverProviderService> logger, HomeserverResolverService homeserverResolverService) {
-        Console.WriteLine("Homeserver provider service instantiated!");
-        _tieredStorageService = tieredStorageService;
-        _logger = logger;
-        _homeserverResolverService = homeserverResolverService;
-        logger.LogDebug(
-            $"New HomeserverProviderService created with TieredStorageService<{string.Join(", ", tieredStorageService.GetType().GetProperties().Select(x => x.Name))}>!");
-    }
-
-    private static Dictionary<string, SemaphoreSlim> _authenticatedHomeserverSemaphore = new();
-    private static Dictionary<string, AuthenticatedHomeServer> _authenticatedHomeServerCache = new();
-
-    public async Task<AuthenticatedHomeServer> GetAuthenticatedWithToken(string homeserver, string accessToken,
-        string? overrideFullDomain = null) {
-        SemaphoreSlim sem = _authenticatedHomeserverSemaphore.GetOrCreate(homeserver+accessToken, _ => new SemaphoreSlim(1, 1));
-        await sem.WaitAsync();
-        if (_authenticatedHomeServerCache.ContainsKey(homeserver+accessToken)) {
-            sem.Release();
-            return _authenticatedHomeServerCache[homeserver+accessToken];
-        }
-
-        var hs = new AuthenticatedHomeServer(_tieredStorageService, homeserver, accessToken);
-        hs.FullHomeServerDomain = overrideFullDomain ??
-                                  await _homeserverResolverService.ResolveHomeserverFromWellKnown(homeserver);
-        hs._httpClient.Dispose();
-        hs._httpClient = new MatrixHttpClient { BaseAddress = new Uri(hs.FullHomeServerDomain) };
-        hs._httpClient.Timeout = TimeSpan.FromSeconds(120);
-        hs._httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
-
-        hs.WhoAmI = (await hs._httpClient.GetFromJsonAsync<WhoAmIResponse>("/_matrix/client/v3/account/whoami"))!;
-
-        _authenticatedHomeServerCache[homeserver+accessToken] = hs;
-        sem.Release();
-
-        return hs;
-    }
-
-    public async Task<RemoteHomeServer> GetRemoteHomeserver(string homeserver, string? overrideFullDomain = null) {
-        var hs = new RemoteHomeServer(homeserver);
-        hs.FullHomeServerDomain = overrideFullDomain ??
-                                  await _homeserverResolverService.ResolveHomeserverFromWellKnown(homeserver);
-        hs._httpClient.Dispose();
-        hs._httpClient = new MatrixHttpClient { BaseAddress = new Uri(hs.FullHomeServerDomain) };
-        hs._httpClient.Timeout = TimeSpan.FromSeconds(120);
-        return hs;
-    }
-
-    public async Task<LoginResponse> Login(string homeserver, string user, string password,
-        string? overrideFullDomain = null) {
-        var hs = await GetRemoteHomeserver(homeserver, overrideFullDomain);
-        var payload = new LoginRequest {
-            Identifier = new() { User = user },
-            Password = password
-        };
-        var resp = await hs._httpClient.PostAsJsonAsync("/_matrix/client/v3/login", payload);
-        var data = await resp.Content.ReadFromJsonAsync<LoginResponse>();
-        return data!;
-    }
-
-    private class LoginRequest {
-        [JsonPropertyName("type")]
-        public string Type { get; set; } = "m.login.password";
-
-        [JsonPropertyName("identifier")]
-        public LoginIdentifier Identifier { get; set; } = new();
-
-        [JsonPropertyName("password")]
-        public string Password { get; set; } = "";
-
-        [JsonPropertyName("initial_device_display_name")]
-        public string InitialDeviceDisplayName { get; set; } = "Rory&::LibMatrix";
-
-        public class LoginIdentifier {
-            [JsonPropertyName("type")]
-            public string Type { get; set; } = "m.id.user";
-
-            [JsonPropertyName("user")]
-            public string User { get; set; } = "";
-        }
-    }
-}
diff --git a/MatrixRoomUtils.Core/Services/HomeserverResolverService.cs b/MatrixRoomUtils.Core/Services/HomeserverResolverService.cs
deleted file mode 100644
index 5856000..0000000
--- a/MatrixRoomUtils.Core/Services/HomeserverResolverService.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-using System.Net.Http.Json;
-using System.Text.Json;
-using MatrixRoomUtils.Core.Extensions;
-using Microsoft.Extensions.Logging;
-
-namespace MatrixRoomUtils.Core.Services;
-
-public class HomeserverResolverService {
-    private readonly MatrixHttpClient _httpClient = new();
-    private readonly ILogger<HomeserverResolverService> _logger;
-
-    private static readonly Dictionary<string, string> _wellKnownCache = new();
-    private static readonly Dictionary<string, SemaphoreSlim> _wellKnownSemaphores = new();
-
-    public HomeserverResolverService(ILogger<HomeserverResolverService> logger) {
-        _logger = logger;
-    }
-
-    public async Task<string> ResolveHomeserverFromWellKnown(string homeserver) {
-        var res = await _resolveHomeserverFromWellKnown(homeserver);
-        if (!res.StartsWith("http")) res = "https://" + res;
-        if (res.EndsWith(":443")) res = res.Substring(0, res.Length - 4);
-        return res;
-    }
-
-    private async Task<string> _resolveHomeserverFromWellKnown(string homeserver) {
-        if (homeserver is null) throw new ArgumentNullException(nameof(homeserver));
-        SemaphoreSlim sem = _wellKnownSemaphores.GetOrCreate(homeserver, _ => new SemaphoreSlim(1, 1));
-        await sem.WaitAsync();
-        if (_wellKnownCache.ContainsKey(homeserver)) {
-            sem.Release();
-            return _wellKnownCache[homeserver];
-        }
-
-        string? result = null;
-        _logger.LogInformation($"Attempting to resolve homeserver: {homeserver}");
-        result ??= await _tryResolveFromClientWellknown(homeserver);
-        result ??= await _tryResolveFromServerWellknown(homeserver);
-        result ??= await _tryCheckIfDomainHasHomeserver(homeserver);
-
-        if (result is not null) {
-            _logger.LogInformation($"Resolved homeserver: {homeserver} -> {result}");
-            _wellKnownCache[homeserver] = result;
-            sem.Release();
-            return result;
-        }
-
-        throw new InvalidDataException($"Failed to resolve homeserver for {homeserver}! Is it online and configured correctly?");
-    }
-
-    private async Task<string?> _tryResolveFromClientWellknown(string homeserver) {
-        if (!homeserver.StartsWith("http")) homeserver = "https://" + homeserver;
-        if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/client")) {
-            var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/client");
-            var hs = resp.GetProperty("m.homeserver").GetProperty("base_url").GetString();
-            return hs;
-        }
-
-        _logger.LogInformation("No client well-known...");
-        return null;
-    }
-
-    private async Task<string?> _tryResolveFromServerWellknown(string homeserver) {
-        if (!homeserver.StartsWith("http")) homeserver = "https://" + homeserver;
-        if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/server")) {
-            var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/server");
-            var hs = resp.GetProperty("m.server").GetString();
-            return hs;
-        }
-
-        _logger.LogInformation("No server well-known...");
-        return null;
-    }
-
-    private async Task<string?> _tryCheckIfDomainHasHomeserver(string homeserver) {
-        _logger.LogInformation($"Checking if {homeserver} hosts a homeserver...");
-        if (await _httpClient.CheckSuccessStatus($"{homeserver}/_matrix/client/versions"))
-            return homeserver;
-        _logger.LogInformation("No homeserver on shortname...");
-        return null;
-    }
-
-    private async Task<string?> _tryCheckIfSubDomainHasHomeserver(string homeserver, string subdomain) {
-        homeserver = homeserver.Replace("https://", $"https://{subdomain}.");
-        return await _tryCheckIfDomainHasHomeserver(homeserver);
-    }
-}
diff --git a/MatrixRoomUtils.Core/Services/ServiceInstaller.cs b/MatrixRoomUtils.Core/Services/ServiceInstaller.cs
deleted file mode 100644
index bd5b1bd..0000000
--- a/MatrixRoomUtils.Core/Services/ServiceInstaller.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using MatrixRoomUtils.Core.Extensions;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace MatrixRoomUtils.Core.Services;
-
-public static class ServiceInstaller {
-
-    public static IServiceCollection AddRoryLibMatrixServices(this IServiceCollection services, RoryLibMatrixConfiguration? config = null) {
-        //Check required services
-        if (!services.Any(x => x.ServiceType == typeof(TieredStorageService)))
-            throw new Exception("[MRUCore/DI] No TieredStorageService has been registered!");
-        //Add config
-        if(config is not null)
-            services.AddSingleton(config);
-        else {
-            services.AddSingleton(new RoryLibMatrixConfiguration());
-        }
-        //Add services
-        services.AddSingleton<HomeserverProviderService>();
-        services.AddSingleton<HomeserverResolverService>();
-        // services.AddScoped<MatrixHttpClient>();
-        return services;
-    }
-
-
-}
-
-public class RoryLibMatrixConfiguration {
-    public string AppName { get; set; } = "Rory&::LibMatrix";
-}
diff --git a/MatrixRoomUtils.Core/Services/TieredStorageService.cs b/MatrixRoomUtils.Core/Services/TieredStorageService.cs
deleted file mode 100644
index 2f27443..0000000
--- a/MatrixRoomUtils.Core/Services/TieredStorageService.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using MatrixRoomUtils.Core.Interfaces.Services;
-
-namespace MatrixRoomUtils.Core.Services; 
-
-public class TieredStorageService {
-    public IStorageProvider CacheStorageProvider { get; }
-    public IStorageProvider DataStorageProvider { get; }
-
-    public TieredStorageService(IStorageProvider cacheStorageProvider, IStorageProvider dataStorageProvider) {
-        CacheStorageProvider = cacheStorageProvider;
-        DataStorageProvider = dataStorageProvider;
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEvent.cs b/MatrixRoomUtils.Core/StateEvent.cs
deleted file mode 100644
index 785c637..0000000
--- a/MatrixRoomUtils.Core/StateEvent.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-using System.Diagnostics;
-using System.Reflection;
-using System.Text.Json;
-using System.Text.Json.Nodes;
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.StateEventTypes;
-
-namespace MatrixRoomUtils.Core;
-
-public class StateEvent {
-    public static List<Type> KnownStateEventTypes =
-        new ClassCollector<IStateEventType>().ResolveFromAllAccessibleAssemblies();
-
-    public static Type GetStateEventType(string type) {
-        if (type == "m.receipt") {
-            return typeof(Dictionary<string, JsonObject>);
-        }
-
-        var eventType = KnownStateEventTypes.FirstOrDefault(x =>
-            x.GetCustomAttributes<MatrixEventAttribute>()?.Any(y => y.EventName == type) ?? false);
-
-        return eventType ?? typeof(object);
-    }
-
-    public object TypedContent {
-        get {
-            try {
-                return RawContent.Deserialize(GetType)!;
-            }
-            catch (JsonException e) {
-                Console.WriteLine(e);
-                Console.WriteLine("Content:\n" + ObjectExtensions.ToJson(RawContent));
-            }
-
-            return null;
-        }
-        set => RawContent = JsonSerializer.Deserialize<JsonObject>(JsonSerializer.Serialize(value));
-    }
-
-    [JsonPropertyName("state_key")]
-    public string StateKey { get; set; } = "";
-
-    private string _type;
-
-    [JsonPropertyName("type")]
-    public string Type {
-        get => _type;
-        set {
-            _type = value;
-            // if (RawContent is not null && this is StateEventResponse stateEventResponse) {
-            //     if (File.Exists($"unknown_state_events/{Type}/{stateEventResponse.EventId}.json")) return;
-            //     var x = GetType.Name;
-            // }
-        }
-    }
-
-    [JsonPropertyName("replaces_state")]
-    public string? ReplacesState { get; set; }
-
-    private JsonObject? _rawContent;
-
-    [JsonPropertyName("content")]
-    public JsonObject? RawContent {
-        get => _rawContent;
-        set {
-            _rawContent = value;
-            // if (Type is not null && this is StateEventResponse stateEventResponse) {
-            //     if (File.Exists($"unknown_state_events/{Type}/{stateEventResponse.EventId}.json")) return;
-            //     var x = GetType.Name;
-            // }
-        }
-    }
-
-    [JsonIgnore]
-    public Type GetType {
-        get {
-            var type = GetStateEventType(Type);
-
-            //special handling for some types
-            // if (type == typeof(RoomEmotesEventData)) {
-            //     RawContent["emote"] = RawContent["emote"]?.AsObject() ?? new JsonObject();
-            // }
-            //
-            // if (this is StateEventResponse stateEventResponse) {
-            //     if (type == null || type == typeof(object)) {
-            //         Console.WriteLine($"Warning: unknown event type '{Type}'!");
-            //         Console.WriteLine(RawContent.ToJson());
-            //         Directory.CreateDirectory($"unknown_state_events/{Type}");
-            //         File.WriteAllText($"unknown_state_events/{Type}/{stateEventResponse.EventId}.json",
-            //             RawContent.ToJson());
-            //         Console.WriteLine($"Saved to unknown_state_events/{Type}/{stateEventResponse.EventId}.json");
-            //     }
-            //     else if (RawContent is not null && RawContent.FindExtraJsonObjectFields(type)) {
-            //         Directory.CreateDirectory($"unknown_state_events/{Type}");
-            //         File.WriteAllText($"unknown_state_events/{Type}/{stateEventResponse.EventId}.json",
-            //             RawContent.ToJson());
-            //         Console.WriteLine($"Saved to unknown_state_events/{Type}/{stateEventResponse.EventId}.json");
-            //     }
-            // }
-
-            return type;
-        }
-    }
-
-    //debug
-    public string dtype {
-        get {
-            var res = GetType().Name switch {
-                "StateEvent`1" => $"StateEvent",
-                _ => GetType().Name
-            };
-            return res;
-        }
-    }
-
-    public string cdtype => TypedContent.GetType().Name;
-}
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs
deleted file mode 100644
index 66dcdb9..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Common;
-
-[MatrixEvent(EventName = "org.matrix.mjolnir.shortcode")]
-public class MjolnirShortcodeEventData : IStateEventType {
-    [JsonPropertyName("shortcode")]
-    public string? Shortcode { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs
deleted file mode 100644
index c263a3a..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Common;
-
-[MatrixEvent(EventName = "im.ponies.room_emotes")]
-public class RoomEmotesEventData : IStateEventType {
-    [JsonPropertyName("emoticons")]
-    public Dictionary<string, EmoticonData>? Emoticons { get; set; }
-
-    [JsonPropertyName("images")]
-    public Dictionary<string, EmoticonData>? Images { get; set; }
-
-    [JsonPropertyName("pack")]
-    public PackInfo? Pack { get; set; }
-
-    public class EmoticonData {
-        [JsonPropertyName("url")]
-        public string? Url { get; set; }
-    }
-
-    public class PackInfo {
-
-    }
-}
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs
deleted file mode 100644
index 354f99d..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.room.canonical_alias")]
-public class CanonicalAliasEventData : IStateEventType {
-    [JsonPropertyName("alias")]
-    public string? Alias { get; set; }
-    [JsonPropertyName("alt_aliases")]
-    public string[]? AltAliases { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessEventData.cs
deleted file mode 100644
index c5b92ad..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessEventData.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.guest_access")]
-public class GuestAccessEventData : IStateEventType {
-    [JsonPropertyName("guest_access")]
-    public string GuestAccess { get; set; }
-
-    public bool IsGuestAccessEnabled {
-        get => GuestAccess == "can_join";
-        set => GuestAccess = value ? "can_join" : "forbidden";
-    }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityEventData.cs
deleted file mode 100644
index e0785b9..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityEventData.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.history_visibility")]
-public class HistoryVisibilityEventData : IStateEventType {
-    [JsonPropertyName("history_visibility")]
-    public string HistoryVisibility { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/JoinRulesEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/JoinRulesEventData.cs
deleted file mode 100644
index f5410dc..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/JoinRulesEventData.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.join_rules")]
-public class JoinRulesEventData : IStateEventType {
-    private static string Public = "public";
-    private static string Invite = "invite";
-    private static string Knock = "knock";
-
-    [JsonPropertyName("join_rule")]
-    public string JoinRule { get; set; }
-
-    [JsonPropertyName("allow")]
-    public List<string> Allow { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs
deleted file mode 100644
index ef94cff..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.policy.rule.user")]
-[MatrixEvent(EventName = "m.policy.rule.server")]
-[MatrixEvent(EventName = "org.matrix.mjolnir.rule.server")]
-public class PolicyRuleStateEventData : IStateEventType {
-    /// <summary>
-    ///     Entity this ban applies to, can use * and ? as globs.
-    /// </summary>
-    [JsonPropertyName("entity")]
-    public string Entity { get; set; }
-
-    /// <summary>
-    ///     Reason this user is banned
-    /// </summary>
-    [JsonPropertyName("reason")]
-    public string? Reason { get; set; }
-
-    /// <summary>
-    ///     Suggested action to take
-    /// </summary>
-    [JsonPropertyName("recommendation")]
-    public string? Recommendation { get; set; }
-
-    /// <summary>
-    ///     Expiry time in milliseconds since the unix epoch, or null if the ban has no expiry.
-    /// </summary>
-    [JsonPropertyName("support.feline.policy.expiry.rev.2")] //stable prefix: expiry, msc pending
-    public long? Expiry { get; set; }
-
-    //utils
-    /// <summary>
-    ///     Readable expiry time, provided for easy interaction
-    /// </summary>
-    [JsonPropertyName("gay.rory.matrix_room_utils.readable_expiry_time_utc")]
-    public DateTime? ExpiryDateTime {
-        get => Expiry == null ? null : DateTimeOffset.FromUnixTimeMilliseconds(Expiry.Value).DateTime;
-        set => Expiry = ((DateTimeOffset)value).ToUnixTimeMilliseconds();
-    }
-}
-
-public static class PolicyRecommendationTypes {
-    /// <summary>
-    ///     Ban this user
-    /// </summary>
-    public static string Ban = "m.ban";
-
-    /// <summary>
-    ///     Mute this user
-    /// </summary>
-    public static string Mute = "support.feline.policy.recommendation_mute"; //stable prefix: m.mute, msc pending
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs
deleted file mode 100644
index c5eb2ea..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.presence")]
-public class PresenceStateEventData : IStateEventType {
-    [JsonPropertyName("presence")]
-    public string Presence { get; set; }
-    [JsonPropertyName("last_active_ago")]
-    public long LastActiveAgo { get; set; }
-    [JsonPropertyName("currently_active")]
-    public bool CurrentlyActive { get; set; }
-    [JsonPropertyName("status_msg")]
-    public string StatusMessage { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponseEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponseEventData.cs
deleted file mode 100644
index f3a0ce9..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponseEventData.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-public class ProfileResponseEventData : IStateEventType {
-    [JsonPropertyName("avatar_url")]
-    public string? AvatarUrl { get; set; } = "";
-
-    [JsonPropertyName("displayname")]
-    public string? DisplayName { get; set; } = "";
-}
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs
deleted file mode 100644
index 611e8a2..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.alias")]
-public class RoomAliasEventData : IStateEventType {
-    [JsonPropertyName("aliases")]
-    public List<string>? Aliases { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs
deleted file mode 100644
index a14e4c5..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.avatar")]
-public class RoomAvatarEventData : IStateEventType {
-    [JsonPropertyName("url")]
-    public string? Url { get; set; }
-
-    [JsonPropertyName("info")]
-    public RoomAvatarInfo? Info { get; set; }
-
-    public class RoomAvatarInfo {
-        [JsonPropertyName("h")]
-        public int? Height { get; set; }
-
-        [JsonPropertyName("w")]
-        public int? Width { get; set; }
-
-        [JsonPropertyName("mimetype")]
-        public string? MimeType { get; set; }
-
-        [JsonPropertyName("size")]
-        public int? Size { get; set; }
-    }
-}
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs
deleted file mode 100644
index 6127028..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.create")]
-public class RoomCreateEventData : IStateEventType {
-    [JsonPropertyName("room_version")]
-    public string? RoomVersion { get; set; }
-    [JsonPropertyName("creator")]
-    public string? Creator { get; set; }
-    [JsonPropertyName("m.federate")]
-    public bool? Federate { get; set; }
-    [JsonPropertyName("predecessor")]
-    public RoomCreatePredecessor? Predecessor { get; set; }
-    [JsonPropertyName("type")]
-    public string? Type { get; set; }
-
-    public class RoomCreatePredecessor {
-        [JsonPropertyName("room_id")]
-        public string? RoomId { get; set; }
-
-        [JsonPropertyName("event_id")]
-        public string? EventId { get; set; }
-    }
-}
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs
deleted file mode 100644
index c473082..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.room.encryption")]
-public class RoomEncryptionEventData : IStateEventType {
-    [JsonPropertyName("algorithm")]
-    public string? Algorithm { get; set; }
-    [JsonPropertyName("rotation_period_ms")]
-    public ulong? RotationPeriodMs { get; set; }
-    [JsonPropertyName("rotation_period_msgs")]
-    public ulong? RotationPeriodMsgs { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs
deleted file mode 100644
index a543a2f..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.member")]
-public class RoomMemberEventData : IStateEventType {
-    [JsonPropertyName("reason")]
-    public string? Reason { get; set; }
-
-    [JsonPropertyName("membership")]
-    public string Membership { get; set; } = null!;
-
-    [JsonPropertyName("displayname")]
-    public string? Displayname { get; set; }
-
-    [JsonPropertyName("is_direct")]
-    public bool? IsDirect { get; set; }
-
-    [JsonPropertyName("avatar_url")]
-    public string? AvatarUrl { get; set; }
-
-    [JsonPropertyName("kind")]
-    public string? Kind { get; set; }
-    
-    [JsonPropertyName("join_authorised_via_users_server")]
-    public string? JoinAuthorisedViaUsersServer { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMessageEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMessageEventData.cs
deleted file mode 100644
index 2c56b88..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMessageEventData.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.room.message")]
-public class RoomMessageEventData : IStateEventType {
-    [JsonPropertyName("body")]
-    public string Body { get; set; }
-    [JsonPropertyName("msgtype")]
-    public string MessageType { get; set; } = "m.notice";
-
-    [JsonPropertyName("formatted_body")]
-    public string FormattedBody { get; set; }
-
-    [JsonPropertyName("format")]
-    public string Format { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs
deleted file mode 100644
index e5b7d59..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.room.name")]
-public class RoomNameEventData : IStateEventType {
-    [JsonPropertyName("name")]
-    public string? Name { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs
deleted file mode 100644
index d84e962..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.room.pinned_events")]
-public class RoomPinnedEventData : IStateEventType {
-    [JsonPropertyName("pinned")]
-    public string[]? PinnedEvents { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPowerLevelEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPowerLevelEventData.cs
deleted file mode 100644
index 1cde660..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPowerLevelEventData.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.power_levels")]
-public class RoomPowerLevelEventData : IStateEventType {
-    [JsonPropertyName("ban")]
-    public int Ban { get; set; } // = 50;
-
-    [JsonPropertyName("events_default")]
-    public int EventsDefault { get; set; } // = 0;
-
-    [JsonPropertyName("events")]
-    public Dictionary<string, int> Events { get; set; } // = null!;
-
-    [JsonPropertyName("invite")]
-    public int Invite { get; set; } // = 50;
-
-    [JsonPropertyName("kick")]
-    public int Kick { get; set; } // = 50;
-
-    [JsonPropertyName("notifications")]
-    public NotificationsPL NotificationsPl { get; set; } // = null!;
-
-    [JsonPropertyName("redact")]
-    public int Redact { get; set; } // = 50;
-
-    [JsonPropertyName("state_default")]
-    public int StateDefault { get; set; } // = 50;
-
-    [JsonPropertyName("users")]
-    public Dictionary<string, int> Users { get; set; } // = null!;
-
-    [JsonPropertyName("users_default")]
-    public int UsersDefault { get; set; } // = 0;
-
-    [Obsolete("Historical was a key related to MSC2716, a spec change on backfill that was dropped!", true)]
-    [JsonIgnore]
-    [JsonPropertyName("historical")]
-    public int Historical { get; set; } // = 50;
-
-    public class NotificationsPL {
-        [JsonPropertyName("room")]
-        public int Room { get; set; } = 50;
-    }
-
-    public bool IsUserAdmin(string userId) {
-        return Users.TryGetValue(userId, out var level) && level >= Events.Max(x=>x.Value);
-    }
-
-    public bool UserHasPermission(string userId, string eventType) {
-        return Users.TryGetValue(userId, out var level) && level >= Events.GetValueOrDefault(eventType, EventsDefault);
-    }
-}
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs
deleted file mode 100644
index cdd62a1..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.room.topic")]
-[MatrixEvent(EventName = "org.matrix.msc3765.topic", Legacy = true)]
-public class RoomTopicEventData : IStateEventType {
-    [JsonPropertyName("topic")]
-    public string? Topic { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs
deleted file mode 100644
index 017a117..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.typing")]
-public class RoomTypingEventData : IStateEventType {
-    [JsonPropertyName("user_ids")]
-    public string[]? UserIds { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLEventData.cs
deleted file mode 100644
index 4b559c6..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLEventData.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.room.server_acl")]
-public class ServerACLEventData : IStateEventType {
-    [JsonPropertyName("allow")]
-    public List<string> Allow { get; set; } // = null!;
-
-    [JsonPropertyName("deny")]
-    public List<string> Deny { get; set; } // = null!;
-
-    [JsonPropertyName("allow_ip_literals")]
-    public bool AllowIpLiterals { get; set; } // = false;
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs
deleted file mode 100644
index bb62d92..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
-
-[MatrixEvent(EventName = "m.space.child")]
-public class SpaceChildEventData : IStateEventType {
-    [JsonPropertyName("auto_join")]
-    public bool? AutoJoin { get; set; }
-    [JsonPropertyName("via")]
-    public string[]? Via { get; set; }
-    [JsonPropertyName("suggested")]
-    public bool? Suggested { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceParentEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceParentEventData.cs
deleted file mode 100644
index a40f7ae..0000000
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceParentEventData.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Text.Json.Serialization;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces;
-
-namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
-
-[MatrixEvent(EventName = "m.space.parent")]
-public class SpaceParentEventData : IStateEventType {
-    [JsonPropertyName("via")]
-    public string[]? Via { get; set; }
-
-    [JsonPropertyName("canonical")]
-    public bool? Canonical { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/UserIdAndReason.cs b/MatrixRoomUtils.Core/UserIdAndReason.cs
deleted file mode 100644
index 3801077..0000000
--- a/MatrixRoomUtils.Core/UserIdAndReason.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace MatrixRoomUtils.Core;
-
-internal class UserIdAndReason {
-    [JsonPropertyName("user_id")]
-    public string UserId { get; set; }
-    [JsonPropertyName("reason")]
-    public string? Reason { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.DebugDataValidationApi/Controllers/ValidationController.cs b/MatrixRoomUtils.DebugDataValidationApi/Controllers/ValidationController.cs
deleted file mode 100644
index 949871a..0000000
--- a/MatrixRoomUtils.DebugDataValidationApi/Controllers/ValidationController.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Text.Json;
-using MatrixRoomUtils.Core.Extensions;
-using Microsoft.AspNetCore.Mvc;
-
-namespace MatrixRoomUtils.DebugDataValidationApi.Controllers;
-
-[ApiController]
-[Route("/")]
-public class ValidationController : ControllerBase {
-    private readonly ILogger<ValidationController> _logger;
-
-    public ValidationController(ILogger<ValidationController> logger) {
-        _logger = logger;
-    }
-
-    [HttpPost("/validate/{type}")]
-    public async Task<bool> Get([FromRoute] string type, [FromBody] JsonElement content) {
-        Type t = Type.GetType(type);
-        if (t is null) {
-            Console.WriteLine($"Type `{type}` does not exist!");
-            throw new ArgumentException($"Unknown type {type}!");
-        }
-        Console.WriteLine($"Validating {type}...");
-        return content.FindExtraJsonElementFields(t, "$");
-    }
-}
diff --git a/MatrixRoomUtils.DebugDataValidationApi/MatrixRoomUtils.DebugDataValidationApi.csproj b/MatrixRoomUtils.DebugDataValidationApi/MatrixRoomUtils.DebugDataValidationApi.csproj
deleted file mode 100644
index 4c23207..0000000
--- a/MatrixRoomUtils.DebugDataValidationApi/MatrixRoomUtils.DebugDataValidationApi.csproj
+++ /dev/null
@@ -1,19 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
-
-    <PropertyGroup>
-        <TargetFramework>net7.0</TargetFramework>
-        <Nullable>enable</Nullable>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <InvariantGlobalization>true</InvariantGlobalization>
-    </PropertyGroup>
-
-    <ItemGroup>
-        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.9" />
-        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
-    </ItemGroup>
-
-    <ItemGroup>
-      <ProjectReference Include="..\MatrixRoomUtils.Core\MatrixRoomUtils.Core.csproj" />
-    </ItemGroup>
-
-</Project>
diff --git a/MatrixRoomUtils.DebugDataValidationApi/Program.cs b/MatrixRoomUtils.DebugDataValidationApi/Program.cs
deleted file mode 100644
index 047dbcf..0000000
--- a/MatrixRoomUtils.DebugDataValidationApi/Program.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-var builder = WebApplication.CreateBuilder(args);
-
-// Add services to the container.
-
-builder.Services.AddControllers();
-// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
-builder.Services.AddEndpointsApiExplorer();
-builder.Services.AddSwaggerGen();
-builder.Services.AddCors(options =>
-{
-    options.AddPolicy(
-        "Open",
-        builder => builder.AllowAnyOrigin().AllowAnyHeader());
-});
-
-var app = builder.Build();
-
-// Configure the HTTP request pipeline.
-if (app.Environment.IsDevelopment()) {
-    app.UseSwagger();
-    app.UseSwaggerUI();
-}
-
-// app.UseHttpsRedirection();
-
-app.UseCors("Open");
-
-app.UseAuthorization();
-
-app.MapControllers();
-
-app.Run();
diff --git a/MatrixRoomUtils.DebugDataValidationApi/Properties/launchSettings.json b/MatrixRoomUtils.DebugDataValidationApi/Properties/launchSettings.json
deleted file mode 100644
index c33e091..0000000
--- a/MatrixRoomUtils.DebugDataValidationApi/Properties/launchSettings.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "$schema": "http://json.schemastore.org/launchsettings.json",
-  "iisSettings": {
-    "windowsAuthentication": false,
-    "anonymousAuthentication": true,
-    "iisExpress": {
-      "applicationUrl": "http://localhost:63687",
-      "sslPort": 44316
-    }
-  },
-  "profiles": {
-    "http": {
-      "commandName": "Project",
-      "dotnetRunMessages": true,
-      "launchBrowser": false,
-      "launchUrl": "swagger",
-      "applicationUrl": "http://localhost:5116",
-      "environmentVariables": {
-        "ASPNETCORE_ENVIRONMENT": "Development"
-      }
-    },
-    "https": {
-      "commandName": "Project",
-      "dotnetRunMessages": true,
-      "launchBrowser": true,
-      "launchUrl": "swagger",
-      "applicationUrl": "https://localhost:7017;http://localhost:5116",
-      "environmentVariables": {
-        "ASPNETCORE_ENVIRONMENT": "Development"
-      }
-    },
-    "IIS Express": {
-      "commandName": "IISExpress",
-      "launchBrowser": true,
-      "launchUrl": "swagger",
-      "environmentVariables": {
-        "ASPNETCORE_ENVIRONMENT": "Development"
-      }
-    }
-  }
-}
diff --git a/MatrixRoomUtils.DebugDataValidationApi/appsettings.Development.json b/MatrixRoomUtils.DebugDataValidationApi/appsettings.Development.json
deleted file mode 100644
index 12c8ab9..0000000
--- a/MatrixRoomUtils.DebugDataValidationApi/appsettings.Development.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "Logging": {
-    "LogLevel": {
-      "Default": "Information",
-      "Microsoft.AspNetCore": "Information",
-      "Microsoft.AspNetCore.Routing": "Warning",
-      "Microsoft.AspNetCore.Mvc": "Warning",
-      "Microsoft.AspNetCore.Cors": "Warning"
-    }
-  }
-}
diff --git a/MatrixRoomUtils.DebugDataValidationApi/appsettings.json b/MatrixRoomUtils.DebugDataValidationApi/appsettings.json
deleted file mode 100644
index 10f68b8..0000000
--- a/MatrixRoomUtils.DebugDataValidationApi/appsettings.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "Logging": {
-    "LogLevel": {
-      "Default": "Information",
-      "Microsoft.AspNetCore": "Warning"
-    }
-  },
-  "AllowedHosts": "*"
-}
diff --git a/MatrixRoomUtils.Desktop/App.axaml.cs b/MatrixRoomUtils.Desktop/App.axaml.cs
index 3fe8862..20f2a3c 100644
--- a/MatrixRoomUtils.Desktop/App.axaml.cs
+++ b/MatrixRoomUtils.Desktop/App.axaml.cs
@@ -1,7 +1,7 @@
 using Avalonia;
 using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Markup.Xaml;
-using MatrixRoomUtils.Core.Services;
+using LibMatrix.Services;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
 using Sentry;
diff --git a/MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs b/MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs
index a447701..f29db63 100644
--- a/MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs
+++ b/MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs
@@ -1,10 +1,10 @@
 using Avalonia.Controls;
 using Avalonia.Interactivity;
 using Avalonia.Media.Imaging;
-using MatrixRoomUtils.Core;
-using MatrixRoomUtils.Core.Helpers;
-using MatrixRoomUtils.Core.Services;
-using MatrixRoomUtils.Core.StateEventTypes.Spec;
+using LibMatrix;
+using LibMatrix.Helpers;
+using LibMatrix.Services;
+using LibMatrix.StateEventTypes.Spec;
 using MatrixRoomUtils.Web.Classes;
 using Microsoft.Extensions.DependencyInjection;
 
diff --git a/MatrixRoomUtils.Desktop/FileStorageProvider.cs b/MatrixRoomUtils.Desktop/FileStorageProvider.cs
index 6c44fd2..36a3c7e 100644
--- a/MatrixRoomUtils.Desktop/FileStorageProvider.cs
+++ b/MatrixRoomUtils.Desktop/FileStorageProvider.cs
@@ -1,6 +1,6 @@
 using System.Text.Json;
-using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Interfaces.Services;
+using LibMatrix.Extensions;
+using LibMatrix.Interfaces.Services;
 using Microsoft.Extensions.Logging;
 
 namespace MatrixRoomUtils.Desktop;
diff --git a/MatrixRoomUtils.Desktop/MRUStorageWrapper.cs b/MatrixRoomUtils.Desktop/MRUStorageWrapper.cs
index a5494ad..5444f24 100644
--- a/MatrixRoomUtils.Desktop/MRUStorageWrapper.cs
+++ b/MatrixRoomUtils.Desktop/MRUStorageWrapper.cs
@@ -1,6 +1,6 @@
-using MatrixRoomUtils.Core;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.Services;
+using LibMatrix;
+using LibMatrix.Responses;
+using LibMatrix.Services;
 
 namespace MatrixRoomUtils.Desktop;
 
diff --git a/MatrixRoomUtils.Desktop/MainWindow.axaml.cs b/MatrixRoomUtils.Desktop/MainWindow.axaml.cs
index f89bbfa..89f9d52 100644
--- a/MatrixRoomUtils.Desktop/MainWindow.axaml.cs
+++ b/MatrixRoomUtils.Desktop/MainWindow.axaml.cs
@@ -25,8 +25,8 @@ public partial class MainWindow : Window {
 
         InitializeComponent();
 
-        _logger.LogInformation("Cache location: " + _configuration.CacheStoragePath);
-        _logger.LogInformation("Data location: " + _configuration.DataStoragePath);
+        _logger.LogInformation("Cache location: {}", _configuration.CacheStoragePath);
+        _logger.LogInformation("Data location: {}", _configuration.DataStoragePath);
 
 
         // for (int i = 0; i < 100; i++) {
@@ -40,7 +40,7 @@ public partial class MainWindow : Window {
         var hs = await _storageWrapper.GetCurrentSessionOrPrompt();
         var rooms = await hs.GetJoinedRooms();
         foreach (var room in rooms) {
-            roomList.Children.Add(new RoomListEntry(_scopeFactory, new RoomInfo(room)));
+            // roomList.Children.Add(new RoomListEntry(_scopeFactory, new RoomInfo(room)));
         }
         base.OnLoaded(e);
     }
diff --git a/MatrixRoomUtils.Desktop/MatrixRoomUtils.Desktop.csproj b/MatrixRoomUtils.Desktop/MatrixRoomUtils.Desktop.csproj
index 6f3e256..e6a8169 100644
--- a/MatrixRoomUtils.Desktop/MatrixRoomUtils.Desktop.csproj
+++ b/MatrixRoomUtils.Desktop/MatrixRoomUtils.Desktop.csproj
@@ -31,7 +31,7 @@
 
 
     <ItemGroup>
-        <ProjectReference Include="..\MatrixRoomUtils.Core\MatrixRoomUtils.Core.csproj" />
+        <ProjectReference Include="..\LibMatrix\LibMatrix\LibMatrix.csproj" />
     </ItemGroup>
 
     <ItemGroup>
diff --git a/MatrixRoomUtils.Desktop/RoomInfo.cs b/MatrixRoomUtils.Desktop/RoomInfo.cs
index a31d67a..fdd7d03 100644
--- a/MatrixRoomUtils.Desktop/RoomInfo.cs
+++ b/MatrixRoomUtils.Desktop/RoomInfo.cs
@@ -1,7 +1,6 @@
-using MatrixRoomUtils.Core;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.RoomTypes;
+using LibMatrix;
+using LibMatrix.Responses;
+using LibMatrix.RoomTypes;
 
 namespace MatrixRoomUtils.Web.Classes;
 
diff --git a/MatrixRoomUtils.Web/Classes/LocalStorageProviderService.cs b/MatrixRoomUtils.Web/Classes/LocalStorageProviderService.cs
index 256c43d..02d691a 100644
--- a/MatrixRoomUtils.Web/Classes/LocalStorageProviderService.cs
+++ b/MatrixRoomUtils.Web/Classes/LocalStorageProviderService.cs
@@ -1,7 +1,7 @@
 using Blazored.LocalStorage;
-using MatrixRoomUtils.Core.Interfaces.Services;
+using LibMatrix.Interfaces.Services;
 
-namespace MatrixRoomUtils.Web.Classes; 
+namespace MatrixRoomUtils.Web.Classes;
 
 public class LocalStorageProviderService : IStorageProvider {
     private readonly ILocalStorageService _localStorageService;
@@ -23,4 +23,4 @@ public class LocalStorageProviderService : IStorageProvider {
     async Task<List<string>> IStorageProvider.GetAllKeysAsync() => (await _localStorageService.KeysAsync()).ToList();
 
     async Task IStorageProvider.DeleteObjectAsync(string key) => await _localStorageService.RemoveItemAsync(key);
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs b/MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs
index d4b256b..e9d56b9 100644
--- a/MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs
+++ b/MatrixRoomUtils.Web/Classes/MRUStorageWrapper.cs
@@ -1,6 +1,6 @@
-using MatrixRoomUtils.Core;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.Services;
+using LibMatrix;
+using LibMatrix.Responses;
+using LibMatrix.Services;
 using Microsoft.AspNetCore.Components;
 
 namespace MatrixRoomUtils.Web.Classes;
diff --git a/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs b/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs
index f895173..b6f6d56 100644
--- a/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs
+++ b/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs
@@ -1,8 +1,8 @@
 using System.Text.Json.Nodes;
-using MatrixRoomUtils.Core;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.StateEventTypes;
-using MatrixRoomUtils.Core.StateEventTypes.Spec;
+using LibMatrix;
+using LibMatrix.Responses;
+using LibMatrix.StateEventTypes.Spec;
+using LibMatrix.StateEventTypes;
 
 namespace MatrixRoomUtils.Web.Classes.RoomCreationTemplates;
 
@@ -89,4 +89,4 @@ public class DefaultRoomCreationTemplate : IRoomCreationTemplate {
                 }
             }
         };
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/IRoomCreationTemplate.cs b/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/IRoomCreationTemplate.cs
index bbb09b7..42503f7 100644
--- a/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/IRoomCreationTemplate.cs
+++ b/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/IRoomCreationTemplate.cs
@@ -1,8 +1,8 @@
-using MatrixRoomUtils.Core.Responses;
+using LibMatrix.Responses;
 
 namespace MatrixRoomUtils.Web.Classes.RoomCreationTemplates;
 
 public interface IRoomCreationTemplate {
     public CreateRoomRequest CreateRoomRequest { get; }
     public string Name { get; }
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Classes/RoomInfo.cs b/MatrixRoomUtils.Web/Classes/RoomInfo.cs
index f9d5452..4df81ec 100644
--- a/MatrixRoomUtils.Web/Classes/RoomInfo.cs
+++ b/MatrixRoomUtils.Web/Classes/RoomInfo.cs
@@ -1,7 +1,6 @@
-using MatrixRoomUtils.Core;
-using MatrixRoomUtils.Core.Interfaces;
-using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.RoomTypes;
+using LibMatrix;
+using LibMatrix.Responses;
+using LibMatrix.RoomTypes;
 
 namespace MatrixRoomUtils.Web.Classes;
 
diff --git a/MatrixRoomUtils.Web/Classes/SessionStorageProviderService.cs b/MatrixRoomUtils.Web/Classes/SessionStorageProviderService.cs
index e497ee3..6f11cad 100644
--- a/MatrixRoomUtils.Web/Classes/SessionStorageProviderService.cs
+++ b/MatrixRoomUtils.Web/Classes/SessionStorageProviderService.cs
@@ -1,7 +1,7 @@
 using Blazored.SessionStorage;
-using MatrixRoomUtils.Core.Interfaces.Services;
+using LibMatrix.Interfaces.Services;
 
-namespace MatrixRoomUtils.Web.Classes; 
+namespace MatrixRoomUtils.Web.Classes;
 
 public class SessionStorageProviderService : IStorageProvider {
     private readonly ISessionStorageService _sessionStorageService;
@@ -9,7 +9,7 @@ public class SessionStorageProviderService : IStorageProvider {
     public SessionStorageProviderService(ISessionStorageService sessionStorage) {
         _sessionStorageService = sessionStorage;
     }
-    
+
     async Task IStorageProvider.SaveAllChildrenAsync<T>(string key, T value) => throw new NotImplementedException();
 
     async Task<T?> IStorageProvider.LoadAllChildrenAsync<T>(string key) where T : default => throw new NotImplementedException();
@@ -23,4 +23,4 @@ public class SessionStorageProviderService : IStorageProvider {
     async Task<List<string>> IStorageProvider.GetAllKeysAsync() => (await _sessionStorageService.KeysAsync()).ToList();
 
     async Task IStorageProvider.DeleteObjectAsync(string key) => await _sessionStorageService.RemoveItemAsync(key);
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
index 4b874c9..e6580e9 100644
--- a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
+++ b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
@@ -14,7 +14,7 @@
     </ItemGroup>
 
     <ItemGroup>
-        <ProjectReference Include="..\MatrixRoomUtils.Core\MatrixRoomUtils.Core.csproj" />
+        <ProjectReference Include="..\LibMatrix\LibMatrix\LibMatrix.csproj" />
     </ItemGroup>
 
 </Project>
diff --git a/MatrixRoomUtils.Web/Pages/DebugTools.razor b/MatrixRoomUtils.Web/Pages/DebugTools.razor
index 5116754..afb1da2 100644
--- a/MatrixRoomUtils.Web/Pages/DebugTools.razor
+++ b/MatrixRoomUtils.Web/Pages/DebugTools.razor
@@ -1,6 +1,7 @@
 @page "/Debug"
 @using System.Reflection
-@using MatrixRoomUtils.Core.Interfaces
+@using LibMatrix.Extensions
+@using LibMatrix.Interfaces
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 <h3>Debug Tools</h3>
@@ -74,4 +75,4 @@ else {
         StateHasChanged();
     }
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Pages/DevOptions.razor b/MatrixRoomUtils.Web/Pages/DevOptions.razor
index 70dac31..bf499a3 100644
--- a/MatrixRoomUtils.Web/Pages/DevOptions.razor
+++ b/MatrixRoomUtils.Web/Pages/DevOptions.razor
@@ -1,4 +1,5 @@
 @page "/DevOptions"
+@using LibMatrix.Extensions
 @inject NavigationManager NavigationManager
 @inject ILocalStorageService LocalStorage
 
@@ -26,4 +27,4 @@
         await TieredStorage.DataStorageProvider.SaveObjectAsync("mru.settings", settings);
     }
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor b/MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor
index e3ebc72..b2928ee 100644
--- a/MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor
+++ b/MatrixRoomUtils.Web/Pages/HSAdmin/RoomQuery.razor
@@ -1,7 +1,8 @@
 @page "/HSAdmin/RoomQuery"
-@using MatrixRoomUtils.Core.Filters
-@using MatrixRoomUtils.Core.Responses.Admin
 @using MatrixRoomUtils.Web.Shared.SimpleComponents
+@using LibMatrix.Responses.Admin
+@using LibMatrix.Filters
+@using LibMatrix.Extensions
 
 <h3>Homeserver Administration - Room Query</h3>
 
@@ -121,7 +122,7 @@
     .tile150 {
         min-width: 150px;
     }
-    .range-sep { 
+    .range-sep {
         display: inline-block;
         padding: 4px;
         width: 150px;
@@ -193,4 +194,4 @@
         { "state_events", "Number of state events" }
     };
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor
index 01e2be4..65ba68b 100644
--- a/MatrixRoomUtils.Web/Pages/Index.razor
+++ b/MatrixRoomUtils.Web/Pages/Index.razor
@@ -1,7 +1,8 @@
 @page "/"
-@using MatrixRoomUtils.Core.Helpers
-@using MatrixRoomUtils.Core.Responses
 @using MatrixRoomUtils.Web.Shared.SimpleComponents
+@using LibMatrix.Responses
+@using LibMatrix
+@using LibMatrix.Helpers
 
 <PageTitle>Index</PageTitle>
 
diff --git a/MatrixRoomUtils.Web/Pages/InvalidSession.razor b/MatrixRoomUtils.Web/Pages/InvalidSession.razor
index 3bcd797..2b030ce 100644
--- a/MatrixRoomUtils.Web/Pages/InvalidSession.razor
+++ b/MatrixRoomUtils.Web/Pages/InvalidSession.razor
@@ -1,7 +1,7 @@
 @page "/InvalidSession"
-@using MatrixRoomUtils.Core.Helpers
-@using MatrixRoomUtils.Core.Responses
 @using MatrixRoomUtils.Web.Shared.SimpleComponents
+@using LibMatrix.Responses
+@using LibMatrix
 
 <PageTitle>Invalid session</PageTitle>
 
diff --git a/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor b/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor
index 5ccecab..10a2929 100644
--- a/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor
+++ b/MatrixRoomUtils.Web/Pages/KnownHomeserverList.razor
@@ -1,8 +1,10 @@
 @page "/KnownHomeserverList"
 @using System.Text.Json
 @using System.Diagnostics
-@using MatrixRoomUtils.Core.Responses
-@using MatrixRoomUtils.Core.StateEventTypes
+@using LibMatrix
+@using LibMatrix.Extensions
+@using LibMatrix.RoomTypes
+@using LibMatrix.StateEventTypes
 <h3>Known Homeserver List</h3>
 <hr/>
 
@@ -62,7 +64,7 @@ else {
     private async Task<List<HomeServerInfo>> GetHomeservers(int memberLimit = 1000, Func<HomeServerInfoQueryProgress, Task<bool>>? progressCallback = null) {
         HomeServerInfoQueryProgress progress = new();
         List<HomeServerInfo> homeServers = new();
-        
+
         var rooms = await hs.GetJoinedRooms();
         progress.TotalRooms = rooms.Count;
 
@@ -168,4 +170,4 @@ else {
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Pages/LoginPage.razor b/MatrixRoomUtils.Web/Pages/LoginPage.razor
index e19dd04..9730cbe 100644
--- a/MatrixRoomUtils.Web/Pages/LoginPage.razor
+++ b/MatrixRoomUtils.Web/Pages/LoginPage.razor
@@ -1,6 +1,6 @@
 @page "/Login"
 @using System.Text.Json
-@using MatrixRoomUtils.Core.Responses
+@using LibMatrix.Responses
 @using MatrixRoomUtils.Web.Shared.SimpleComponents
 @inject ILocalStorageService LocalStorage
 @inject IJSRuntime JsRuntime
@@ -49,7 +49,7 @@
     (string homeserver, string username, string password) newRecordInput = ("", "", "");
 
     List<LoginResponse> LoggedInSessions { get; set; } = new();
-    
+
     async Task Login() {
         var loginTasks = records.Select(async record => {
             var (homeserver, username, password) = record;
@@ -97,4 +97,4 @@
         newRecordInput = ("", "", "");
     }
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Pages/MediaLocator.razor b/MatrixRoomUtils.Web/Pages/MediaLocator.razor
index 6221041..8c41440 100644
--- a/MatrixRoomUtils.Web/Pages/MediaLocator.razor
+++ b/MatrixRoomUtils.Web/Pages/MediaLocator.razor
@@ -1,4 +1,5 @@
 @page "/MediaLocator"
+@using LibMatrix
 @inject HttpClient Http
 <h3>Media locator</h3>
 <hr/>
@@ -106,4 +107,4 @@
         StateHasChanged();
     }
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
index 3a98801..ebf6444 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
@@ -1,10 +1,12 @@
 @page "/Rooms/Create"
-@using MatrixRoomUtils.Core.Responses
 @using System.Text.Json
 @using System.Reflection
-@using MatrixRoomUtils.Core.Helpers
-@using MatrixRoomUtils.Core.StateEventTypes
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix
+@using LibMatrix.Extensions
+@using LibMatrix.Helpers
+@using LibMatrix.Responses
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix.StateEventTypes
 @using MatrixRoomUtils.Web.Classes.RoomCreationTemplates
 @* @* ReSharper disable once RedundantUsingDirective - Must not remove this, Rider marks this as "unused" when it's not */ *@
 @using MatrixRoomUtils.Web.Shared.SimpleComponents
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
index 6d12dc2..89ededf 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
@@ -1,9 +1,9 @@
 @page "/Rooms"
-@using MatrixRoomUtils.Core.StateEventTypes
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
-@using MatrixRoomUtils.Core.Filters
-@using MatrixRoomUtils.Core.Helpers
-@using MatrixRoomUtils.Core.Responses
+@using LibMatrix.StateEventTypes
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix.Filters
+@using LibMatrix.Helpers
+@using LibMatrix.Responses
 <h3>Room list</h3>
 <p>@Status</p>
 @if (RenderContents) {
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor
index cd4788b..3297bcb 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor
@@ -1,9 +1,11 @@
 @page "/Rooms/{RoomId}/Policies"
-@using MatrixRoomUtils.Core.StateEventTypes
+@using LibMatrix.StateEventTypes
 @using System.Text.Json
-@using MatrixRoomUtils.Core.Helpers
-@using MatrixRoomUtils.Core.Responses
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix
+@using LibMatrix.Extensions
+@using LibMatrix.Helpers
+@using LibMatrix.Responses
+@using LibMatrix.StateEventTypes.Spec
 <h3>Policy list editor - Editing @RoomId</h3>
 <hr/>
 
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Space.razor b/MatrixRoomUtils.Web/Pages/Rooms/Space.razor
index 91f97d0..15c7c70 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Space.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Space.razor
@@ -1,6 +1,8 @@
 @page "/Rooms/{RoomId}/Space"
 @using System.Text.Json
-@using MatrixRoomUtils.Core.Responses
+@using LibMatrix.Extensions
+@using LibMatrix.Responses
+@using LibMatrix.RoomTypes
 <h3>Room manager - Viewing Space</h3>
 
 <button onclick="@JoinAllRooms">Join all rooms</button>
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor b/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor
index 8b2ff0c..e01fca8 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor
@@ -1,7 +1,8 @@
 @page "/Rooms/{RoomId}/State/Edit"
 @using System.Net.Http.Headers
 @using System.Text.Json
-@using MatrixRoomUtils.Core.Responses
+@using LibMatrix.Extensions
+@using LibMatrix.Responses
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 <h3>Room state editor - Editing @RoomId</h3>
@@ -142,4 +143,4 @@
     }
 
     private string shownEventJson { get; set; }
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor b/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor
index 09b38f0..cf23c36 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor
@@ -1,7 +1,8 @@
 @page "/Rooms/{RoomId}/State/View"
 @using System.Net.Http.Headers
 @using System.Text.Json
-@using MatrixRoomUtils.Core.Responses
+@using LibMatrix.Extensions
+@using LibMatrix.Responses
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 <h3>Room state viewer - Viewing @RoomId</h3>
@@ -125,4 +126,4 @@
     }
 
     private bool _showMembershipEvents;
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor b/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor
index 2234dd9..7fe89cc 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor
@@ -1,7 +1,8 @@
 @page "/Rooms/{RoomId}/Timeline"
 @using MatrixRoomUtils.Web.Shared.TimelineComponents
-@using MatrixRoomUtils.Core.Responses
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix
+@using LibMatrix.Responses
+@using LibMatrix.StateEventTypes.Spec
 <h3>RoomManagerTimeline</h3>
 <hr/>
 <p>Loaded @Events.Count events...</p>
diff --git a/MatrixRoomUtils.Web/Program.cs b/MatrixRoomUtils.Web/Program.cs
index 54d4f0d..c760108 100644
--- a/MatrixRoomUtils.Web/Program.cs
+++ b/MatrixRoomUtils.Web/Program.cs
@@ -2,7 +2,7 @@ using System.Text.Json;
 using System.Text.Json.Serialization;
 using Blazored.LocalStorage;
 using Blazored.SessionStorage;
-using MatrixRoomUtils.Core.Services;
+using LibMatrix.Services;
 using MatrixRoomUtils.Web;
 using MatrixRoomUtils.Web.Classes;
 using Microsoft.AspNetCore.Components.Web;
@@ -41,4 +41,4 @@ builder.Services.AddScoped<TieredStorageService>(x =>
 
 builder.Services.AddRoryLibMatrixServices();
 builder.Services.AddScoped<MRUStorageWrapper>();
-await builder.Build().RunAsync();
\ No newline at end of file
+await builder.Build().RunAsync();
diff --git a/MatrixRoomUtils.Web/Shared/InlineUserItem.razor b/MatrixRoomUtils.Web/Shared/InlineUserItem.razor
index 25db838..f3a7162 100644
--- a/MatrixRoomUtils.Web/Shared/InlineUserItem.razor
+++ b/MatrixRoomUtils.Web/Shared/InlineUserItem.razor
@@ -1,7 +1,7 @@
-@using MatrixRoomUtils.Core.Responses
-@using MatrixRoomUtils.Core.StateEventTypes
-@using MatrixRoomUtils.Core.Helpers
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix.StateEventTypes
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix
+@using LibMatrix.Helpers
 <div style="background-color: #ffffff11; border-radius: 0.5em; height: 1em; display: inline-block; vertical-align: middle;" alt="@UserId">
     <img style="@(ChildContent is not null ? "vertical-align: baseline;" : "vertical-align: top;") width: 1em; height: 1em; border-radius: 50%;" src="@ProfileAvatar"/>
     <span style="position: relative; top: -5px;">@ProfileName</span>
diff --git a/MatrixRoomUtils.Web/Shared/ModalWindow.razor b/MatrixRoomUtils.Web/Shared/ModalWindow.razor
index b40d246..2f001e1 100644
--- a/MatrixRoomUtils.Web/Shared/ModalWindow.razor
+++ b/MatrixRoomUtils.Web/Shared/ModalWindow.razor
@@ -1,3 +1,4 @@
+@using LibMatrix.Extensions
 <div class="r-modal" style="top: @(_y)px; left: @(_x)px;">
     <div class="titlebar" @onmousedown="MouseDown" @onmouseup="MouseUp" @onmousemove="MouseMove" @onmouseleave="MouseMove">
         <b class="title" @ref="_titleRef">@Title</b>
diff --git a/MatrixRoomUtils.Web/Shared/RoomList.razor b/MatrixRoomUtils.Web/Shared/RoomList.razor
index e3894a6..dc06d90 100644
--- a/MatrixRoomUtils.Web/Shared/RoomList.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomList.razor
@@ -1,7 +1,8 @@
 @using MatrixRoomUtils.Web.Shared.RoomListComponents;
-@using MatrixRoomUtils.Core.StateEventTypes
-@using MatrixRoomUtils.Core.StateEventTypes.Common
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix.StateEventTypes
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix
+@using LibMatrix.Extensions
 @if(Rooms.Count != RoomsWithTypes.Sum(x=>x.Value.Count)) {
     <p>Fetching room details... @RoomsWithTypes.Sum(x=>x.Value.Count) out of @Rooms.Count done!</p>
     @foreach (var category in RoomsWithTypes.OrderBy(x => x.Value.Count)) {
diff --git a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
index b798d49..c04df3f 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
@@ -1,6 +1,7 @@
-@using MatrixRoomUtils.Core.StateEventTypes
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix.StateEventTypes
 @using MatrixRoomUtils.Web.Classes.Constants
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix
 <details>
     <summary>@roomType (@rooms.Count)</summary>
     @foreach (var room in rooms) {
diff --git a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor
index f05ac7b..7afdc8c 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListPolicyRoom.razor
@@ -1,3 +1,4 @@
+@using LibMatrix.RoomTypes
 <LinkButton href="@($"/Rooms/{Room.RoomId}/Policies")">Manage policies</LinkButton>
 
 @code {
@@ -9,4 +10,4 @@
         await base.OnInitializedAsync();
     }
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
index e12f622..6e3adc6 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListItem.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
@@ -1,8 +1,9 @@
-@using MatrixRoomUtils.Core.Extensions
 @using System.Text.Json
-@using MatrixRoomUtils.Core.Helpers
-@using MatrixRoomUtils.Core.StateEventTypes
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix
+@using LibMatrix.Helpers
+@using LibMatrix.RoomTypes
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix.StateEventTypes
 @using MatrixRoomUtils.Web.Classes.Constants
 <div class="roomListItem" id="@RoomId" style="background-color: #ffffff11; border-radius: 25px; margin: 8px; width: fit-Content; @(hasDangerousRoomVersion ? "border: red 4px solid;" : hasOldRoomVersion ? "border: #FF0 1px solid;" : "")">
     @if (OwnMemberState != null) {
diff --git a/MatrixRoomUtils.Web/Shared/SimpleComponents/DictionaryEditor.razor b/MatrixRoomUtils.Web/Shared/SimpleComponents/DictionaryEditor.razor
index ea7d2ec..afd1fdc 100644
--- a/MatrixRoomUtils.Web/Shared/SimpleComponents/DictionaryEditor.razor
+++ b/MatrixRoomUtils.Web/Shared/SimpleComponents/DictionaryEditor.razor
@@ -1,3 +1,4 @@
+@using LibMatrix.Extensions
 <table>
     @foreach (var i in Items.Keys) {
         var key = i;
@@ -34,4 +35,4 @@
         ItemsChanged.InvokeAsync();
     }
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor b/MatrixRoomUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor
index 920a38d..5172fa4 100644
--- a/MatrixRoomUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor
+++ b/MatrixRoomUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor
@@ -1,4 +1,5 @@
-@using MatrixRoomUtils.Core.Responses
+@using LibMatrix.Responses
+@using LibMatrix
 <h3>BaseTimelineItem</h3>
 
 @code {
diff --git a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor
index 44eb06e..8239367 100644
--- a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor
+++ b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor
@@ -1,6 +1,6 @@
-@using MatrixRoomUtils.Core.Responses
-@using MatrixRoomUtils.Core.StateEventTypes
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix.StateEventTypes
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix.Extensions
 @inherits BaseTimelineItem
 
 @if (roomMemberData is not null) {
diff --git a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMessageItem.razor b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMessageItem.razor
index bf0e083..411b750 100644
--- a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMessageItem.razor
+++ b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMessageItem.razor
@@ -1,4 +1,4 @@
-@using MatrixRoomUtils.Core.Responses
+@using LibMatrix.Extensions
 @inherits BaseTimelineItem
 
 <pre>
diff --git a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineRoomCreateItem.razor b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineRoomCreateItem.razor
index de204a3..b20cc1a 100644
--- a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineRoomCreateItem.razor
+++ b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineRoomCreateItem.razor
@@ -1,5 +1,5 @@
-@using MatrixRoomUtils.Core.Responses
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix.Extensions
 @inherits BaseTimelineItem
 
 <p>
diff --git a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineUnknownItem.razor b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineUnknownItem.razor
index d0871c3..8166f8a 100644
--- a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineUnknownItem.razor
+++ b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineUnknownItem.razor
@@ -1,3 +1,4 @@
+@using LibMatrix.Extensions
 @inherits BaseTimelineItem
 
 <div>
diff --git a/MatrixRoomUtils.Web/Shared/UserListItem.razor b/MatrixRoomUtils.Web/Shared/UserListItem.razor
index 20b1c8c..a85a68d 100644
--- a/MatrixRoomUtils.Web/Shared/UserListItem.razor
+++ b/MatrixRoomUtils.Web/Shared/UserListItem.razor
@@ -1,7 +1,6 @@
-@using MatrixRoomUtils.Core.Responses
-@using MatrixRoomUtils.Core.StateEventTypes
-@using MatrixRoomUtils.Core.Helpers
-@using MatrixRoomUtils.Core.StateEventTypes.Spec
+@using LibMatrix.StateEventTypes
+@using LibMatrix.StateEventTypes.Spec
+@using LibMatrix.Helpers
 <div style="background-color: #ffffff11; border-radius: 25px; margin: 8px; width: fit-Content;">
     <img style="@(ChildContent is not null ? "vertical-align: baseline;" : "") width: 32px; height:  32px; border-radius: 50%;" src="@profileAvatar"/>
     <span style="vertical-align: middle; margin-right: 8px; border-radius: 75px;">@profileName</span>
@@ -35,7 +34,7 @@
 
         var hs = await MRUStorage.GetCurrentSessionOrNavigate();
         if (hs is null) return;
-        
+
         await _semaphoreSlim.WaitAsync();
 
         if (User == null) {
@@ -52,4 +51,4 @@
         _semaphoreSlim.Release();
     }
 
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/_Imports.razor b/MatrixRoomUtils.Web/_Imports.razor
index b1d9212..cb08515 100644
--- a/MatrixRoomUtils.Web/_Imports.razor
+++ b/MatrixRoomUtils.Web/_Imports.razor
@@ -1,7 +1,7 @@
 @using System.Net.Http
 @using System.Net.Http.Json
 @using Blazored.LocalStorage
-@using MatrixRoomUtils.Core
+@using LibMatrix.Services
 @using Microsoft.AspNetCore.Components.Forms
 @using Microsoft.AspNetCore.Components.Routing
 @using Microsoft.AspNetCore.Components.Web
@@ -11,9 +11,6 @@
 @using MatrixRoomUtils.Web
 @using MatrixRoomUtils.Web.Classes
 @using MatrixRoomUtils.Web.Shared
-@using MatrixRoomUtils.Core.RoomTypes
-@using MatrixRoomUtils.Core.Extensions
-@using MatrixRoomUtils.Core.Services
 
 @using LinkButton = MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton
 
diff --git a/MatrixRoomUtils.Web/deps.nix b/MatrixRoomUtils.Web/deps.nix
new file mode 100644
index 0000000..f300724
--- /dev/null
+++ b/MatrixRoomUtils.Web/deps.nix
@@ -0,0 +1,49 @@
+{ fetchNuGet }: [
+  (fetchNuGet { pname = "Blazored.LocalStorage"; version = "4.3.0"; sha256 = "086zf61frl1rhvppgns0lf9vjacx71z1qc8s4br8x22987ggzbj1"; })
+  (fetchNuGet { pname = "Blazored.SessionStorage"; version = "2.3.0"; sha256 = "1fw7pmsf63cqkxpymgxbm4lvvp3770rza2ag968vrcm723jpbw29"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.App.Runtime.linux-x64"; version = "7.0.8"; sha256 = "1w4x1spgb4x57qn3d1m9a3gyqnwwfk952kaxg8bqrki20a7qkhl4"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Authorization"; version = "7.0.0"; sha256 = "17q08sk2sfd68yb9iw1i6wkpk85ac8rj9ifrsb38psr44xs7060r"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Authorization"; version = "7.0.1"; sha256 = "0258g82vi5hnhicmdzkq75gdiwb0f5hlf7a75592hdcx23n7pjfx"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Authorization"; version = "7.0.7"; sha256 = "014mqxfic81hzacr1inigzwcl3ij03dzd7x1r1cvmjjw5br31yi1"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components"; version = "7.0.0"; sha256 = "01r1wnzmgfmk21rq8w03i7n9rs4fqipki9f6m6qchp5acdi76kx2"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components"; version = "7.0.1"; sha256 = "0y26ghy62qcqn3346dijppdhb8ipvlgg7sxscbpqsccs2607w97r"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components"; version = "7.0.7"; sha256 = "0mggzxclxzk3ap73r2pilhq9gibjcw6zk2nkm0d6swflcsbaa2d8"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Analyzers"; version = "7.0.0"; sha256 = "1b9cm4wz7h021al9ywpq3jijwh53hcqkf7q2410mwx1l5iibcam9"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Analyzers"; version = "7.0.1"; sha256 = "17f7d2v2akz3d7zihlabjrd3viciilfj5qin9xqk4rzw8qqi2s6x"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Analyzers"; version = "7.0.7"; sha256 = "0w14sv0rvwlghsgyyh2mbr37mi5azg9s84g1bpr8zwvwqdp9xkmk"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Forms"; version = "7.0.0"; sha256 = "0szkcvkdpxrvldx9dzpnyrfgz9sjrl0am6p61z6da4aafrafzys1"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Forms"; version = "7.0.1"; sha256 = "0x6mpaqlrcv2c6gs4arm2smy2c9q9m95jyc20i216hfrigym5vbs"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Forms"; version = "7.0.7"; sha256 = "18g7v868113hh0nkljwsxbpdhiz1d1a8zz305cmnzhhwpqyqfn59"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Web"; version = "7.0.0"; sha256 = "1w3ph80prpx5sb130mkl3zlgspvdhwygljhf3yjxnay2dd05rw0k"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Web"; version = "7.0.1"; sha256 = "1izj62mfn4p98jhjvcr0mhvqyvigpf18hkamm202a2r11j6mvlkq"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.Web"; version = "7.0.7"; sha256 = "06l07l371ap8jl0nyv2w1yjsvpasqvvxdpc3bk3vlxbqa3gyaq9i"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.WebAssembly"; version = "7.0.7"; sha256 = "1fjwiala80ndbbp2wmw9hywq1id7lvqsv0c6g8f60rabhw0kndbm"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Components.WebAssembly.DevServer"; version = "7.0.7"; sha256 = "010a7l3dp7dg5ljsk3iv1yq3qjafzggss1v5hnycrrzklhy67m6d"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Metadata"; version = "7.0.0"; sha256 = "1vnilgndj5cck68a6r3vq40889049w7kmx9jm0c0af4f8xl4rgjz"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Metadata"; version = "7.0.1"; sha256 = "0mbhp8gfjfn7p9snd88zkds0jqcyrmw0zm4lpjq10ss6yiq8pxnj"; })
+  (fetchNuGet { pname = "Microsoft.AspNetCore.Metadata"; version = "7.0.7"; sha256 = "1jd36lxh130m3fighgkmqbahc1qf17jsn18kr44bvi533h2wzqcm"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Configuration"; version = "7.0.0"; sha256 = "0n1grglxql9llmrsbbnlz5chx8mxrb5cpvjngm0hfyrkgzcwz90d"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Configuration.Abstractions"; version = "7.0.0"; sha256 = "1as8cygz0pagg17w22nsf6mb49lr2mcl1x8i3ad1wi8lyzygy1a3"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Configuration.Binder"; version = "7.0.4"; sha256 = "0nj424i9428p5k0vpr7rmqs54fbr31f043y1bpl007g3xmy2xn4p"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Configuration.FileExtensions"; version = "7.0.0"; sha256 = "1fk7dcz6gfhd1k1d8ksz22rnjvj1waqjzk29ym4i3dz73rsq8j1i"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Configuration.Json"; version = "7.0.0"; sha256 = "05zjmrpp99l128wijp1fy8asskc11ls871qaqr4mjnz3gbfycxnj"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.DependencyInjection"; version = "7.0.0"; sha256 = "121zs4jp8iimgbpzm3wsglhjwkc06irg1pxy8c1zcdlsg34cfq1p"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.DependencyInjection.Abstractions"; version = "7.0.0"; sha256 = "181d7mp9307fs17lyy42f8cxnjwysddmpsalky4m0pqxcimnr6g7"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Abstractions"; version = "7.0.0"; sha256 = "0ff20yklyjgyjzdyv7sybczgqhgd557m05dbwxzjznr0x41b180d"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.FileProviders.Physical"; version = "7.0.0"; sha256 = "1f1h0l47abw0spssd64qkhgd7b54pyzslyb586zp21milimcfmgv"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.FileSystemGlobbing"; version = "7.0.0"; sha256 = "1812vnkn8n0i4yr3k5azcxcfx1bbpcsmms95rdyxjfrzfksr05ai"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Logging"; version = "7.0.0"; sha256 = "1bqd3pqn5dacgnkq0grc17cgb2i0w8z1raw12nwm3p3zhrfcvgxf"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Logging.Abstractions"; version = "7.0.0"; sha256 = "1gn7d18i1wfy13vrwhmdv1rmsb4vrk26kqdld4cgvh77yigj90xs"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Logging.Abstractions"; version = "7.0.1"; sha256 = "0xv3sqc1lbx5j4yy6g2w3kakzvrpwqs2ihax6lqasj5sz5map6fk"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Options"; version = "7.0.0"; sha256 = "0b90zkrsk5dw3wr749rbynhpxlg4bgqdnd7d5vdlw2g9c7zlhgx6"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Options"; version = "7.0.1"; sha256 = "0ghz4y4gxnf2vw8yvhz9nkw21p6q2qqwh19phkk1xwxywyilr3mq"; })
+  (fetchNuGet { pname = "Microsoft.Extensions.Primitives"; version = "7.0.0"; sha256 = "1b4km9fszid9vp2zb3gya5ni9fn8bq62bzaas2ck2r7gs0sdys80"; })
+  (fetchNuGet { pname = "Microsoft.JSInterop"; version = "7.0.0"; sha256 = "11215mbpdzwijikvhd30lzrarg07h94l0993gh94n6yvxp3b6wrp"; })
+  (fetchNuGet { pname = "Microsoft.JSInterop"; version = "7.0.1"; sha256 = "0xkggwxd55azqcrwibvjzd4pksprlsk0331vfqrj7hsn7dlbrjkc"; })
+  (fetchNuGet { pname = "Microsoft.JSInterop"; version = "7.0.7"; sha256 = "1pnmm8yyn5w3zr2war9jg33yjnvr24d27axsgybpx8n109hgs4aq"; })
+  (fetchNuGet { pname = "Microsoft.JSInterop.WebAssembly"; version = "7.0.7"; sha256 = "06vx3amlfavww1xy1jnhrj8q9x4vkacrkgfwvylxj12ji8ski65q"; })
+  (fetchNuGet { pname = "Microsoft.NETCore.App.Runtime.Mono.linux-x64"; version = "7.0.8"; sha256 = "1dflhc1dfral612bdqxhm8dznyphvnl56ywjjak6s9nsjc4q8h0s"; })
+  (fetchNuGet { pname = "System.IO.Pipelines"; version = "7.0.0"; sha256 = "1ila2vgi1w435j7g2y7ykp2pdbh9c5a02vm85vql89az93b7qvav"; })
+  (fetchNuGet { pname = "System.Text.Encodings.Web"; version = "7.0.0"; sha256 = "1151hbyrcf8kyg1jz8k9awpbic98lwz9x129rg7zk1wrs6vjlpxl"; })
+  (fetchNuGet { pname = "System.Text.Json"; version = "7.0.0"; sha256 = "0scb0lp7wbgcinaa4kqiqs7b8i5nx4ppfad81138jiwd1sl37pyp"; })
+]
diff --git a/MatrixRoomUtils.sln b/MatrixRoomUtils.sln
index ff16a2b..2bf2656 100755
--- a/MatrixRoomUtils.sln
+++ b/MatrixRoomUtils.sln
@@ -4,15 +4,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils", "MatrixRo
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils.Web", "MatrixRoomUtils.Web\MatrixRoomUtils.Web.csproj", "{D38DA95D-DD83-4340-96A4-6F59FC6AE3D9}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils.Core", "MatrixRoomUtils.Core\MatrixRoomUtils.Core.csproj", "{CE777A1E-2CDC-431D-82BF-CC2812E2F3A4}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils.Web.Server", "MatrixRoomUtils.Web.Server\MatrixRoomUtils.Web.Server.csproj", "{F997F26F-2EC1-4D18-B3DD-C46FB2AD65C0}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils.Bot", "MatrixRoomUtils.Bot\MatrixRoomUtils.Bot.csproj", "{B397700A-4ABB-4CAF-8DB8-06E01F44514B}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils.Desktop", "MatrixRoomUtils.Desktop\MatrixRoomUtils.Desktop.csproj", "{27C08A4F-5AF0-4C2C-AFCB-050E3388C116}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils.DebugDataValidationApi", "MatrixRoomUtils.DebugDataValidationApi\MatrixRoomUtils.DebugDataValidationApi.csproj", "{FB0CF653-FD25-4701-9477-1E80221346DB}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LibMatrix", "LibMatrix", "{8F4F6BEC-0C66-486B-A21A-1C35B2EDAD33}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixRoomUtils.Desktop", "MatrixRoomUtils.Desktop\MatrixRoomUtils.Desktop.csproj", "{27C08A4F-5AF0-4C2C-AFCB-050E3388C116}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibMatrix", "LibMatrix\LibMatrix\LibMatrix.csproj", "{F4E241C3-0300-4B87-8707-BCBDEF1F0185}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibMatrix.ExampleBot", "LibMatrix\LibMatrix.ExampleBot\LibMatrix.ExampleBot.csproj", "{4E72793A-AFAD-4E46-B406-2DF1E49994C6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibMatrix.DebugDataValidationApi", "LibMatrix\LibMatrix.DebugDataValidationApi\LibMatrix.DebugDataValidationApi.csproj", "{7762FD80-E7AA-409D-A465-CF208EA4BC53}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -28,25 +30,30 @@ Global
 		{D38DA95D-DD83-4340-96A4-6F59FC6AE3D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{D38DA95D-DD83-4340-96A4-6F59FC6AE3D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{D38DA95D-DD83-4340-96A4-6F59FC6AE3D9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{CE777A1E-2CDC-431D-82BF-CC2812E2F3A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{CE777A1E-2CDC-431D-82BF-CC2812E2F3A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{CE777A1E-2CDC-431D-82BF-CC2812E2F3A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{CE777A1E-2CDC-431D-82BF-CC2812E2F3A4}.Release|Any CPU.Build.0 = Release|Any CPU
 		{F997F26F-2EC1-4D18-B3DD-C46FB2AD65C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{F997F26F-2EC1-4D18-B3DD-C46FB2AD65C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{F997F26F-2EC1-4D18-B3DD-C46FB2AD65C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{F997F26F-2EC1-4D18-B3DD-C46FB2AD65C0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B397700A-4ABB-4CAF-8DB8-06E01F44514B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B397700A-4ABB-4CAF-8DB8-06E01F44514B}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B397700A-4ABB-4CAF-8DB8-06E01F44514B}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B397700A-4ABB-4CAF-8DB8-06E01F44514B}.Release|Any CPU.Build.0 = Release|Any CPU
-		{FB0CF653-FD25-4701-9477-1E80221346DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{FB0CF653-FD25-4701-9477-1E80221346DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{FB0CF653-FD25-4701-9477-1E80221346DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{FB0CF653-FD25-4701-9477-1E80221346DB}.Release|Any CPU.Build.0 = Release|Any CPU
 		{27C08A4F-5AF0-4C2C-AFCB-050E3388C116}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{27C08A4F-5AF0-4C2C-AFCB-050E3388C116}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{27C08A4F-5AF0-4C2C-AFCB-050E3388C116}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{27C08A4F-5AF0-4C2C-AFCB-050E3388C116}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F4E241C3-0300-4B87-8707-BCBDEF1F0185}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F4E241C3-0300-4B87-8707-BCBDEF1F0185}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F4E241C3-0300-4B87-8707-BCBDEF1F0185}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F4E241C3-0300-4B87-8707-BCBDEF1F0185}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4E72793A-AFAD-4E46-B406-2DF1E49994C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4E72793A-AFAD-4E46-B406-2DF1E49994C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4E72793A-AFAD-4E46-B406-2DF1E49994C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4E72793A-AFAD-4E46-B406-2DF1E49994C6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7762FD80-E7AA-409D-A465-CF208EA4BC53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7762FD80-E7AA-409D-A465-CF208EA4BC53}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7762FD80-E7AA-409D-A465-CF208EA4BC53}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7762FD80-E7AA-409D-A465-CF208EA4BC53}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{F4E241C3-0300-4B87-8707-BCBDEF1F0185} = {8F4F6BEC-0C66-486B-A21A-1C35B2EDAD33}
+		{4E72793A-AFAD-4E46-B406-2DF1E49994C6} = {8F4F6BEC-0C66-486B-A21A-1C35B2EDAD33}
+		{7762FD80-E7AA-409D-A465-CF208EA4BC53} = {8F4F6BEC-0C66-486B-A21A-1C35B2EDAD33}
 	EndGlobalSection
 EndGlobal
diff --git a/flake.lock b/flake.lock
index ba339ba..c6625fe 100644
--- a/flake.lock
+++ b/flake.lock
@@ -20,11 +20,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1689850295,
-        "narHash": "sha256-fUYf6WdQlhd2H+3aR8jST5dhFH1d0eE22aes8fNIfyk=",
+        "lastModified": 1691899779,
+        "narHash": "sha256-IBf4KVr/UQJlzrqB2/IHtlvmwsvyIVLPerSzCPU/6Xk=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "5df4d78d54f7a34e9ea1f84a22b4fd9baebc68d0",
+        "rev": "100a1550b0e7a64b960c625b656f9229bdef5f87",
         "type": "github"
       },
       "original": {
diff --git a/flake.nix b/flake.nix
index 34110de..47ab31d 100644
--- a/flake.nix
+++ b/flake.nix
@@ -24,16 +24,16 @@
               #  pkg-config
               #];
             };
-            frontend = pkgs.buildDotnetModule rec {
-              pname = "botcore-v${version}";
-              version = "4";
+            web = pkgs.buildDotnetModule rec {
+              pname = "MatrixRoomUtils.Web-v${version}";
+              version = "1";
               dotnet-sdk = pkgs.dotnet-sdk_7;
               dotnet-runtime = pkgs.dotnet-aspnetcore_7;
               src = ./.;
               projectFile = [
-                "BotCore.Web.Legacy/BotCore.Web.Legacy.csproj"
+                "MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj"
                ];
-              nugetDeps = ./deps.nix;
+              nugetDeps = MatrixRoomUtils.Web/deps.nix;
               #nativeBuildInputs = with pkgs; [
               #  pkg-config
               #];
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..37704f0
--- /dev/null
+++ b/global.json
@@ -0,0 +1,7 @@
+{
+  "sdk": {
+    "version": "7.0.0",
+    "rollForward": "latestMajor",
+    "allowPrerelease": true
+  }
+}
diff --git a/mkdeps b/mkdeps
index b577e03..e6bea58 100755
--- a/mkdeps
+++ b/mkdeps
@@ -1,11 +1,28 @@
 #!/usr/bin/env nix-shell
-#!nix-shell -i "bash -x" -p bash nuget-to-nix
+#!nix-shell -i "bash -x" -p bash nuget-to-nix git dotnet-sdk_7 nix curl jq yq
+projects=(
+  MatrixRoomUtils.Web
+)
+
 find . | grep -E '(bin|obj)$' | while read d; do rm -rf $d & done
 wait
 
-MSBUILDLIVELOGGER=false dotnet restore --packages=packages -v n --ucr
-nuget-to-nix packages | tee deps.nix
-du -sh packages
-rm -rf packages
-nix flake update
-git add deps.nix flake.lock
+execDir=$(pwd)
+
+for p in $projects
+do
+  (
+    cd $p
+    pwd
+    MSBUILDLIVELOGGER=false dotnet restore --packages=packages -v n --ucr
+    #dotnet --list-sdks
+    ${execDir}/nuget-to-nix.sh packages | tee deps.nix
+    #where nuget-to-nix
+    pwd
+    du -sh packages
+    rm -rf packages
+    git add deps.nix
+  )
+  nix flake update
+  git add flake.lock
+done
diff --git a/nuget-to-nix.sh b/nuget-to-nix.sh
new file mode 100755
index 0000000..7aa35fb
--- /dev/null
+++ b/nuget-to-nix.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+
+#patched version of nuget-to-nix to inherit env
+
+set -euo pipefail
+shopt -s nullglob
+
+#export PATH="@binPath@"
+# used for glob ordering of package names
+export LC_ALL=C
+
+if [ $# -eq 0 ]; then
+  >&2 echo "Usage: $0 <packages directory> [path to a file with a list of excluded packages] > deps.nix"
+  exit 1
+fi
+
+pkgs=$1
+tmp=$(realpath "$(mktemp -td nuget-to-nix.XXXXXX)")
+trap 'rm -r "$tmp"' EXIT
+
+excluded_list=$(realpath "${2:-/dev/null}")
+
+export DOTNET_NOLOGO=1
+export DOTNET_CLI_TELEMETRY_OPTOUT=1
+
+mapfile -t sources < <(dotnet nuget list source --format short | awk '/^E / { print $2 }')
+
+declare -A base_addresses
+
+for index in "${sources[@]}"; do
+  base_addresses[$index]=$(
+    curl --compressed --netrc -fsL "$index" | \
+      jq -r '.resources[] | select(."@type" == "PackageBaseAddress/3.0.0")."@id"')
+done
+
+echo "{ fetchNuGet }: ["
+
+cd "$pkgs"
+for package in *; do
+  cd "$package"
+  for version in *; do
+    id=$(xq -r .package.metadata.id "$version/$package".nuspec)
+
+    if grep -qxF "$id.$version.nupkg" "$excluded_list"; then
+      continue
+    fi
+
+    used_source="$(jq -r '.source' "$version"/.nupkg.metadata)"
+    for source in "${sources[@]}"; do
+      url="${base_addresses[$source]}$package/$version/$package.$version.nupkg"
+      if [[ "$source" == "$used_source" ]]; then
+        sha256="$(nix-hash --type sha256 --flat --base32 "$version/$package.$version".nupkg)"
+        found=true
+        break
+      else
+        if sha256=$(nix-prefetch-url "$url" 2>"$tmp"/error); then
+          # If multiple remote sources are enabled, nuget will try them all
+          # concurrently and use the one that responds first. We always use the
+          # first source that has the package.
+          echo "$package $version is available at $url, but was restored from $used_source" 1>&2
+          found=true
+          break
+        else
+          if ! grep -q 'HTTP error 404' "$tmp/error"; then
+            cat "$tmp/error" 1>&2
+            exit 1
+          fi
+        fi
+      fi
+    done
+
+    if ! ${found-false}; then
+      echo "couldn't find $package $version" >&2
+      exit 1
+    fi
+
+    if [[ "$source" != https://api.nuget.org/v3/index.json ]]; then
+      echo "  (fetchNuGet { pname = \"$id\"; version = \"$version\"; sha256 = \"$sha256\"; url = \"$url\"; })"
+    else
+      echo "  (fetchNuGet { pname = \"$id\"; version = \"$version\"; sha256 = \"$sha256\"; })"
+    fi
+  done
+  cd ..
+done
+
+cat << EOL
+]
+EOL