about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2023-07-02 01:01:09 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2023-07-02 01:01:09 +0200
commitdef33cc092ae2c6defcc218b108b7c99cbfb8581 (patch)
treeba992ff8c30b7d4e8af0a78350e157e095455a18
parentDeduplicate some api calls (diff)
downloadMatrixUtils-def33cc092ae2c6defcc218b108b7c99cbfb8581.tar.xz
Prefetch room info
-rw-r--r--MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs7
-rw-r--r--MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs4
-rw-r--r--MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs6
-rw-r--r--MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs2
-rw-r--r--MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs9
-rw-r--r--MatrixRoomUtils.Bot/Bot/Interfaces/ICommand.cs2
-rw-r--r--MatrixRoomUtils.Bot/Bot/MRUBot.cs57
-rw-r--r--MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs2
-rw-r--r--MatrixRoomUtils.Bot/Program.cs3
-rw-r--r--MatrixRoomUtils.Core/AuthenticatedHomeServer.cs1
-rw-r--r--MatrixRoomUtils.Core/CreateEvent.cs20
-rw-r--r--MatrixRoomUtils.Core/Interfaces/IHomeServer.cs18
-rw-r--r--MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs3
-rw-r--r--MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs20
-rw-r--r--MatrixRoomUtils.Core/Services/HomeserverResolverService.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEvent.cs6
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessEventData.cs (renamed from MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessData.cs)4
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityEventData.cs (renamed from MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityData.cs)4
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/JoinRulesEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/PowerLevelEventData.cs (renamed from MatrixRoomUtils.Core/StateEventTypes/Spec/PowerLevelEvent.cs)4
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponseEventData.cs (renamed from MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponse.cs)5
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMessageEventData.cs (renamed from MatrixRoomUtils.Core/StateEventTypes/Spec/MessageEventData.cs)4
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLData.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs2
-rw-r--r--MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs9
-rw-r--r--MatrixRoomUtils.Web/Classes/RoomInfo.cs29
-rw-r--r--MatrixRoomUtils.Web/Classes/SessionStorageProviderService.cs2
-rw-r--r--MatrixRoomUtils.Web/Pages/ModalTest.razor2
-rw-r--r--MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor107
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor96
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor11
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/Index.razor9
-rw-r--r--MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor (renamed from MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor)3
-rw-r--r--MatrixRoomUtils.Web/Shared/InlineUserItem.razor3
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomList.razor33
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor18
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor18
-rw-r--r--MatrixRoomUtils.Web/Shared/RoomListItem.razor32
-rw-r--r--MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor1
-rw-r--r--MatrixRoomUtils.Web/Shared/UserListItem.razor3
54 files changed, 208 insertions, 385 deletions
diff --git a/MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs b/MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs
index 66f3c4d..79757ae 100644
--- a/MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs
+++ b/MatrixRoomUtils.Bot/Bot/Commands/CmdCommand.cs
@@ -1,9 +1,6 @@
-using System.Runtime.InteropServices;
-using System.Text;
-using MatrixRoomUtils.Bot.Interfaces;
-using Microsoft.Extensions.DependencyInjection;
+using MatrixRoomUtils.Bot.Bot.Interfaces;
 
-namespace MatrixRoomUtils.Bot.Commands;
+namespace MatrixRoomUtils.Bot.Bot.Commands;
 
 public class CmdCommand : ICommand {
     public string Name { get; } = "cmd";
diff --git a/MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs b/MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs
index af41563..6db10ae 100644
--- a/MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs
+++ b/MatrixRoomUtils.Bot/Bot/Commands/HelpCommand.cs
@@ -1,8 +1,8 @@
 using System.Text;
-using MatrixRoomUtils.Bot.Interfaces;
+using MatrixRoomUtils.Bot.Bot.Interfaces;
 using Microsoft.Extensions.DependencyInjection;
 
-namespace MatrixRoomUtils.Bot.Commands; 
+namespace MatrixRoomUtils.Bot.Bot.Commands; 
 
 public class HelpCommand : ICommand {
     private readonly IServiceProvider _services;
diff --git a/MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs b/MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs
index a00cc8b..061ca53 100644
--- a/MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs
+++ b/MatrixRoomUtils.Bot/Bot/Commands/PingCommand.cs
@@ -1,8 +1,6 @@
-using System.Text;
-using MatrixRoomUtils.Bot.Interfaces;
-using Microsoft.Extensions.DependencyInjection;
+using MatrixRoomUtils.Bot.Bot.Interfaces;
 
-namespace MatrixRoomUtils.Bot.Commands; 
+namespace MatrixRoomUtils.Bot.Bot.Commands; 
 
 public class PingCommand : ICommand {
     public PingCommand() {
diff --git a/MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs b/MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs
index 8b9e726..c38591d 100644
--- a/MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs
+++ b/MatrixRoomUtils.Bot/Bot/FileStorageProvider.cs
@@ -3,7 +3,7 @@ using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces.Services;
 using Microsoft.Extensions.Logging;
 
-namespace MatrixRoomUtils.Bot; 
+namespace MatrixRoomUtils.Bot.Bot; 
 
 public class FileStorageProvider : IStorageProvider {
     private readonly ILogger<FileStorageProvider> _logger;
diff --git a/MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs b/MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs
index ab29554..94007a5 100644
--- a/MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs
+++ b/MatrixRoomUtils.Bot/Bot/Interfaces/CommandContext.cs
@@ -1,11 +1,12 @@
-using MatrixRoomUtils.Core;
 using MatrixRoomUtils.Core.Responses;
+using MatrixRoomUtils.Core.RoomTypes;
+using MatrixRoomUtils.Core.StateEventTypes.Spec;
 
-namespace MatrixRoomUtils.Bot.Interfaces;
+namespace MatrixRoomUtils.Bot.Bot.Interfaces;
 
 public class CommandContext {
     public GenericRoom Room { get; set; }
     public StateEventResponse MessageEvent { get; set; }
-    public string CommandName => (MessageEvent.TypedContent as MessageEventData).Body.Split(' ')[0][1..];
-    public string[] Args => (MessageEvent.TypedContent as MessageEventData).Body.Split(' ')[1..];
+    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
index b57d8c9..20805b1 100644
--- a/MatrixRoomUtils.Bot/Bot/Interfaces/ICommand.cs
+++ b/MatrixRoomUtils.Bot/Bot/Interfaces/ICommand.cs
@@ -1,4 +1,4 @@
-namespace MatrixRoomUtils.Bot.Interfaces; 
+namespace MatrixRoomUtils.Bot.Bot.Interfaces; 
 
 public interface ICommand {
     public string Name { get; }
diff --git a/MatrixRoomUtils.Bot/Bot/MRUBot.cs b/MatrixRoomUtils.Bot/Bot/MRUBot.cs
index 134019a..adf825d 100644
--- a/MatrixRoomUtils.Bot/Bot/MRUBot.cs
+++ b/MatrixRoomUtils.Bot/Bot/MRUBot.cs
@@ -1,16 +1,15 @@
-using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
-using MatrixRoomUtils.Bot;
-using MatrixRoomUtils.Bot.Interfaces;
+using MatrixRoomUtils.Bot.Bot.Interfaces;
 using MatrixRoomUtils.Core;
 using MatrixRoomUtils.Core.Extensions;
-using MatrixRoomUtils.Core.Helpers;
 using MatrixRoomUtils.Core.Services;
-using MatrixRoomUtils.Core.StateEventTypes;
+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;
@@ -75,32 +74,32 @@ public class MRUBot : IHostedService {
 
             var room = await hs.GetRoom(@event.RoomId);
             // _logger.LogInformation(eventResponse.ToJson(indent: false));
-            if (@event is { Type: "m.room.message", TypedContent: MessageEventData message }) {
+            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 MessageEventData() {
-                                    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 MessageEventData() {
-                                    MessageType = "m.text",
-                                    Body = "You do not have permission to run this command!"
-                                });
-                        }
+                    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!"
+                            });
+                    }
                 }
             }
         });
diff --git a/MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs b/MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs
index c91698a..418eebb 100644
--- a/MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs
+++ b/MatrixRoomUtils.Bot/Bot/MRUBotConfiguration.cs
@@ -1,6 +1,6 @@
 using Microsoft.Extensions.Configuration;
 
-namespace MatrixRoomUtils.Bot; 
+namespace MatrixRoomUtils.Bot.Bot; 
 
 public class MRUBotConfiguration {
     public MRUBotConfiguration(IConfiguration config) {
diff --git a/MatrixRoomUtils.Bot/Program.cs b/MatrixRoomUtils.Bot/Program.cs
index 0e27286..5dae843 100644
--- a/MatrixRoomUtils.Bot/Program.cs
+++ b/MatrixRoomUtils.Bot/Program.cs
@@ -1,7 +1,8 @@
 // See https://aka.ms/new-console-template for more information

 

 using MatrixRoomUtils.Bot;

-using MatrixRoomUtils.Bot.Interfaces;

+using MatrixRoomUtils.Bot.Bot;

+using MatrixRoomUtils.Bot.Bot.Interfaces;

 using MatrixRoomUtils.Core.Extensions;

 using MatrixRoomUtils.Core.Services;

 using Microsoft.Extensions.DependencyInjection;

diff --git a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs
index 09da766..fbbb99f 100644
--- a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs
+++ b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs
@@ -9,6 +9,7 @@ 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;
diff --git a/MatrixRoomUtils.Core/CreateEvent.cs b/MatrixRoomUtils.Core/CreateEvent.cs
deleted file mode 100644
index a7022c5..0000000
--- a/MatrixRoomUtils.Core/CreateEvent.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace MatrixRoomUtils.Core;
-
-public class CreateEvent {
-    [JsonPropertyName("creator")]
-    public string Creator { get; set; }
-
-    [JsonPropertyName("room_version")]
-    public string RoomVersion { get; set; }
-
-    [JsonPropertyName("type")]
-    public string? Type { get; set; }
-
-    [JsonPropertyName("predecessor")]
-    public object? Predecessor { get; set; }
-
-    [JsonPropertyName("m.federate")]
-    public bool Federate { get; set; }
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
index 4ee2a3e..d41a6cd 100644
--- a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
+++ b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
@@ -2,6 +2,7 @@ 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;
 
@@ -12,27 +13,16 @@ public class IHomeServer {
 
     protected internal MatrixHttpClient _httpClient { get; set; } = new();
 
-    public async Task<ProfileResponse> GetProfile(string mxid, bool debounce = false, bool cache = true) {
-        // if (cache) {
-        //     if (debounce) await Task.Delay(Random.Shared.Next(100, 500));
-        //     if (_profileCache.ContainsKey(mxid)) {
-        //         while (_profileCache[mxid] == null) {
-        //             Console.WriteLine($"Waiting for profile cache for {mxid}, currently {_profileCache[mxid]?.ToJson() ?? "null"} within {_profileCache.Count} profiles...");
-        //             await Task.Delay(Random.Shared.Next(50, 500));
-        //         }
-        //
-        //         return _profileCache[mxid];
-        //     }
-        // }
+    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 ProfileResponse p) return p;
+            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<ProfileResponse>();
+        var data = await resp.Content.ReadFromJsonAsync<ProfileResponseEventData>();
         if (!resp.IsSuccessStatusCode) Console.WriteLine("Profile: " + data);
         _profileCache[mxid] = data;
         
diff --git a/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs b/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs
index 8719b5a..334c05c 100644
--- a/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs
+++ b/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs
@@ -3,6 +3,7 @@ using System.Text.Json.Serialization;
 using System.Text.RegularExpressions;
 using MatrixRoomUtils.Core.Interfaces;
 using MatrixRoomUtils.Core.StateEventTypes;
+using MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 namespace MatrixRoomUtils.Core.Responses;
 
@@ -28,7 +29,7 @@ public class CreateRoomRequest {
     public string Visibility { get; set; } = null!;
 
     [JsonPropertyName("power_level_content_override")]
-    public PowerLevelEvent PowerLevelContentOverride { get; set; } = null!;
+    public PowerLevelEventData PowerLevelContentOverride { get; set; } = null!;
 
     [JsonPropertyName("creation_content")]
     public JsonObject CreationContent { get; set; } = new();
diff --git a/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs b/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs
index 879ae6b..db4d4ce 100644
--- a/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs
+++ b/MatrixRoomUtils.Core/RoomTypes/GenericRoom.cs
@@ -3,11 +3,9 @@ using System.Text.Json;
 using System.Web;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Responses;
-using MatrixRoomUtils.Core.RoomTypes;
-using MatrixRoomUtils.Core.StateEventTypes;
-using Microsoft.Extensions.Logging;
+using MatrixRoomUtils.Core.StateEventTypes.Spec;
 
-namespace MatrixRoomUtils.Core;
+namespace MatrixRoomUtils.Core.RoomTypes;
 
 public class GenericRoom {
     internal readonly AuthenticatedHomeServer _homeServer;
@@ -111,14 +109,14 @@ public class GenericRoom {
     public async Task<JoinRulesEventData> GetJoinRuleAsync() =>
         await GetStateAsync<JoinRulesEventData>("m.room.join_rules");
 
-    public async Task<HistoryVisibilityData?> GetHistoryVisibilityAsync() =>
-        await GetStateAsync<HistoryVisibilityData>("m.room.history_visibility");
+    public async Task<HistoryVisibilityEventData?> GetHistoryVisibilityAsync() =>
+        await GetStateAsync<HistoryVisibilityEventData>("m.room.history_visibility");
 
-    public async Task<GuestAccessData?> GetGuestAccessAsync() =>
-        await GetStateAsync<GuestAccessData>("m.room.guest_access");
+    public async Task<GuestAccessEventData?> GetGuestAccessAsync() =>
+        await GetStateAsync<GuestAccessEventData>("m.room.guest_access");
 
-    public async Task<CreateEvent> GetCreateEventAsync() =>
-        await GetStateAsync<CreateEvent>("m.room.create");
+    public async Task<RoomCreateEventData> GetCreateEventAsync() =>
+        await GetStateAsync<RoomCreateEventData>("m.room.create");
 
     public async Task<string?> GetRoomType() {
         var res = await GetStateAsync<RoomCreateEventData>("m.room.create");
@@ -149,7 +147,7 @@ public class GenericRoom {
         await (await _httpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/state/{eventType}", content))
             .Content.ReadFromJsonAsync<EventIdResponse>();
 
-    public async Task<EventIdResponse> SendMessageEventAsync(string eventType, MessageEventData content) {
+    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>();
diff --git a/MatrixRoomUtils.Core/Services/HomeserverResolverService.cs b/MatrixRoomUtils.Core/Services/HomeserverResolverService.cs
index 526a261..e4d8063 100644
--- a/MatrixRoomUtils.Core/Services/HomeserverResolverService.cs
+++ b/MatrixRoomUtils.Core/Services/HomeserverResolverService.cs
@@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging;
 namespace MatrixRoomUtils.Core.Services; 
 
 public class HomeserverResolverService {
-    private readonly MatrixHttpClient _httpClient = new MatrixHttpClient();
+    private readonly MatrixHttpClient _httpClient = new();
     private readonly ILogger<HomeserverResolverService> _logger;
 
     private static Dictionary<string, object> _wellKnownCache = new();
diff --git a/MatrixRoomUtils.Core/StateEvent.cs b/MatrixRoomUtils.Core/StateEvent.cs
index 18b4632..901a194 100644
--- a/MatrixRoomUtils.Core/StateEvent.cs
+++ b/MatrixRoomUtils.Core/StateEvent.cs
@@ -53,10 +53,6 @@ public class StateEvent {
         }
     }
 
-    public T1 GetContent<T1>() where T1 : IStateEventType {
-        return RawContent.Deserialize<T1>();
-    }
-
     [JsonIgnore]
     public Type GetType {
         get {
@@ -81,7 +77,7 @@ public class StateEvent {
                         RawContent.ToJson());
                     Console.WriteLine($"Saved to unknown_state_events/{Type}/{stateEventResponse.EventId}.json");
                 }
-                else if (RawContent.FindExtraJsonObjectFields(type)) {
+                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());
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs
index efc946d..66dcdb9 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Common/MjolnirShortcodeEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes.Common;
 
 [MatrixEvent(EventName = "org.matrix.mjolnir.shortcode")]
 public class MjolnirShortcodeEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs
index 4a75b98..633998c 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Common/RoomEmotesEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Common; 
 
 [MatrixEvent(EventName = "im.ponies.room_emotes")]
 public class RoomEmotesEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs
index 4d6f9c3..354f99d 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/CanonicalAliasEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.room.canonical_alias")]
 public class CanonicalAliasEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessEventData.cs
index 1727ce9..c5b92ad 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/GuestAccessEventData.cs
@@ -2,10 +2,10 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.room.guest_access")]
-public class GuestAccessData : IStateEventType {
+public class GuestAccessEventData : IStateEventType {
     [JsonPropertyName("guest_access")]
     public string GuestAccess { get; set; }
 
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityEventData.cs
index 2bae838..e0785b9 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/HistoryVisibilityEventData.cs
@@ -2,10 +2,10 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.room.history_visibility")]
-public class HistoryVisibilityData : IStateEventType {
+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
index 590835b..f5410dc 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/JoinRulesEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/JoinRulesEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.room.join_rules")]
 public class JoinRulesEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs
index debbef0..ef94cff 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/PolicyRuleStateEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.policy.rule.user")]
 [MatrixEvent(EventName = "m.policy.rule.server")]
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/PowerLevelEvent.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/PowerLevelEventData.cs
index c6100bb..6846db4 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/PowerLevelEvent.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/PowerLevelEventData.cs
@@ -2,10 +2,10 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.room.power_levels")]
-public class PowerLevelEvent : IStateEventType {
+public class PowerLevelEventData : IStateEventType {
     [JsonPropertyName("ban")]
     public int Ban { get; set; } // = 50;
 
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs
index a17b6f9..c5eb2ea 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/PresenceStateEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.presence")]
 public class PresenceStateEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponse.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponseEventData.cs
index d36ef74..4596de9 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponse.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/ProfileResponseEventData.cs
@@ -1,10 +1,11 @@
 using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
+using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.room.member")]
-public class ProfileResponse {
+public class ProfileResponseEventData : IStateEventType {
     [JsonPropertyName("avatar_url")]
     public string? AvatarUrl { get; set; } = "";
 
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs
index 5141ed2..611e8a2 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAliasEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.room.alias")]
 public class RoomAliasEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs
index 03ce16b..bab297b 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomAvatarEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.room.avatar")]
 public class RoomAvatarEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs
index 2e4bb5a..8b85d69 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomCreateEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.room.create")]
 public class RoomCreateEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs
index 8d0576d..c473082 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomEncryptionEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.room.encryption")]
 public class RoomEncryptionEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs
index 50d9dd2..a543a2f 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMemberEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.room.member")]
 public class RoomMemberEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/MessageEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMessageEventData.cs
index bc1c52b..2c56b88 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/MessageEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomMessageEventData.cs
@@ -2,8 +2,10 @@ 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 MessageEventData : IStateEventType {
+public class RoomMessageEventData : IStateEventType {
     [JsonPropertyName("body")]
     public string Body { get; set; }
     [JsonPropertyName("msgtype")]
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs
index 642b5f9..e5b7d59 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomNameEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.room.name")]
 public class RoomNameEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs
index 05c0048..d84e962 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomPinnedEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.room.pinned_events")]
 public class RoomPinnedEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs
index cc5b35b..cdd62a1 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTopicEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.room.topic")]
 [MatrixEvent(EventName = "org.matrix.msc3765.topic", Legacy = true)]
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs
index eac4af2..017a117 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/RoomTypingEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.typing")]
 public class RoomTypingEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLData.cs
index 41bf0a8..1d56e9c 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/ServerACLData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 [MatrixEvent(EventName = "m.room.server_acl")]
 public class ServerACLData : IStateEventType {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs
index f65cd5b..bb62d92 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/Spec/SpaceChildEventData.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
 using MatrixRoomUtils.Core.Extensions;
 using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils.Core.StateEventTypes; 
+namespace MatrixRoomUtils.Core.StateEventTypes.Spec; 
 
 [MatrixEvent(EventName = "m.space.child")]
 public class SpaceChildEventData : IStateEventType {
diff --git a/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs b/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs
index ca6345f..a519977 100644
--- a/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs
+++ b/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs
@@ -2,6 +2,7 @@ using System.Text.Json.Nodes;
 using MatrixRoomUtils.Core;
 using MatrixRoomUtils.Core.Responses;
 using MatrixRoomUtils.Core.StateEventTypes;
+using MatrixRoomUtils.Core.StateEventTypes.Spec;
 
 namespace MatrixRoomUtils.Web.Classes.RoomCreationTemplates;
 
@@ -9,7 +10,7 @@ public class DefaultRoomCreationTemplate : IRoomCreationTemplate {
     public string Name => "Default";
 
     public CreateRoomRequest CreateRoomRequest =>
-        new CreateRoomRequest {
+        new() {
             Name = "My new room",
             RoomAliasName = "myroom",
             InitialState = new List<StateEvent> {
@@ -21,7 +22,7 @@ public class DefaultRoomCreationTemplate : IRoomCreationTemplate {
                 },
                 new() {
                     Type = "m.room.guest_access",
-                    TypedContent = new GuestAccessData {
+                    TypedContent = new GuestAccessEventData {
                         GuestAccess = "can_join"
                     }
                 },
@@ -47,7 +48,7 @@ public class DefaultRoomCreationTemplate : IRoomCreationTemplate {
                 }
             },
             Visibility = "public",
-            PowerLevelContentOverride = new PowerLevelEvent {
+            PowerLevelContentOverride = new PowerLevelEventData {
                 UsersDefault = 0,
                 EventsDefault = 100,
                 StateDefault = 50,
@@ -55,7 +56,7 @@ public class DefaultRoomCreationTemplate : IRoomCreationTemplate {
                 Redact = 50,
                 Kick = 50,
                 Ban = 50,
-                NotificationsPl = new PowerLevelEvent.NotificationsPL {
+                NotificationsPl = new PowerLevelEventData.NotificationsPL {
                     Room = 50
                 },
                 Events = new Dictionary<string, int> {
diff --git a/MatrixRoomUtils.Web/Classes/RoomInfo.cs b/MatrixRoomUtils.Web/Classes/RoomInfo.cs
new file mode 100644
index 0000000..711bf55
--- /dev/null
+++ b/MatrixRoomUtils.Web/Classes/RoomInfo.cs
@@ -0,0 +1,29 @@
+using MatrixRoomUtils.Core;
+using MatrixRoomUtils.Core.Responses;
+using MatrixRoomUtils.Core.RoomTypes;
+
+namespace MatrixRoomUtils.Web.Classes; 
+
+public class RoomInfo {
+    public GenericRoom Room { get; set; }
+    public List<StateEventResponse?> StateEvents { get; } = new();
+    
+    public async Task<StateEventResponse?> GetStateEvent(string type, string stateKey = "") {
+        var @event = StateEvents.FirstOrDefault(x => x.Type == type && x.StateKey == stateKey);
+        if (@event is not null) return @event;
+        @event = new StateEventResponse() {
+            RoomId = Room.RoomId,
+            Type = type,
+            StateKey = stateKey,
+        };
+        try {
+            @event.TypedContent = await Room.GetStateAsync<object>(type, stateKey);
+        }
+        catch (MatrixException e) {
+            if (e is { ErrorCode: "M_NOT_FOUND" }) @event.TypedContent = default!;
+            else throw;
+        }
+        StateEvents.Add(@event);
+        return @event;
+    }
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Classes/SessionStorageProviderService.cs b/MatrixRoomUtils.Web/Classes/SessionStorageProviderService.cs
index 4a9c7d1..58466c7 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;
 
-namespace MatrixRoomUtils.Web; 
+namespace MatrixRoomUtils.Web.Classes; 
 
 public class SessionStorageProviderService : IStorageProvider {
     private readonly ISessionStorageService _sessionStorage;
diff --git a/MatrixRoomUtils.Web/Pages/ModalTest.razor b/MatrixRoomUtils.Web/Pages/ModalTest.razor
index f32c672..79c7fcd 100644
--- a/MatrixRoomUtils.Web/Pages/ModalTest.razor
+++ b/MatrixRoomUtils.Web/Pages/ModalTest.razor
@@ -16,7 +16,7 @@
 
 @code {
 
-    private Dictionary<int, WindowInfo> _windowInfos = new Dictionary<int, WindowInfo>();
+    private Dictionary<int, WindowInfo> _windowInfos = new();
 
     private class WindowInfo {
         public double X;
diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor
deleted file mode 100644
index 4db2b5a..0000000
--- a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor
+++ /dev/null
@@ -1,107 +0,0 @@
-@page "/PolicyListEditor"
-@using System.Text.Json.Serialization
-@using MatrixRoomUtils.Core.Interfaces
-@using MatrixRoomUtils.Core.StateEventTypes
-@inject ILocalStorageService LocalStorage
-@inject NavigationManager NavigationManager
-<h3>Policy list editor - Room list</h3>
-<hr/>
-
-@if (PolicyRoomList.Count == 0) {
-    <p>No policy rooms found.</p>
-    <p>Loading progress: @checkedRoomCount/@totalRoomCount</p>
-}
-else {
-    @if (checkedRoomCount != totalRoomCount) {
-        <p>Loading progress: @checkedRoomCount/@totalRoomCount</p>
-    }
-    foreach (var s in PolicyRoomList) {
-        <a style="color: unset; text-decoration: unset;" href="/PolicyListEditor/@s.RoomId.Replace('.', '~')">
-            <RoomListItem RoomId="@s.RoomId">
-                <br/>
-                <span>Shortcode: @s.Shortcode</span>
-            </RoomListItem>
-        </a>
-        @* <a href="@(NavigationManager.Uri + "/" + s.RoomId.Replace('.', '~'))">[@s.Shortcode] @s.Name (@s.RoomId)</a> *@
-        @* <br/> *@
-    }
-}
-
-<div style="margin-bottom: 4em;"></div>
-<LogView></LogView>
-
-@code {
-    //get room list
-    // - sync withroom list filter
-    // Type = support.feline.msc3784
-    //support.feline.policy.lists.msc.v1
-
-    public List<PolicyRoomInfo> PolicyRoomList { get; set; } = new();
-
-    private int checkedRoomCount { get; set; }
-    private int totalRoomCount { get; set; }
-
-    protected override async Task OnInitializedAsync() {
-        await base.OnInitializedAsync();
-        var hs = await MRUStorage.GetCurrentSessionOrNavigate();
-        if (hs is null) return;
-        await EnumeratePolicyRooms();
-        Console.WriteLine("Policy list editor initialized!");
-    }
-
-    private async Task EnumeratePolicyRooms() {
-        var hs = await MRUStorage.GetCurrentSession();
-        var rooms = await hs.GetJoinedRooms();
-        totalRoomCount = rooms.Count;
-        StateHasChanged();
-
-        var semaphore = new SemaphoreSlim(8);
-        var tasks = new List<Task<PolicyRoomInfo?>>();
-        foreach (var room in rooms) {
-            tasks.Add(GetPolicyRoomInfo(room.RoomId, semaphore));
-        }
-        var results = await Task.WhenAll(tasks);
-        PolicyRoomList.AddRange(results.Where(x => x is not null).Select(x => x.Value));
-
-        Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}");
-    }
-
-    private async Task<PolicyRoomInfo?> GetPolicyRoomInfo(string room, SemaphoreSlim semaphore) {
-        try {
-            await semaphore.WaitAsync();
-            var hs = await MRUStorage.GetCurrentSession();
-            PolicyRoomInfo roomInfo = new() {
-                RoomId = room
-            };
-            var r = await hs.GetRoom(room);
-            var shortcodeState = await r.GetStateAsync<MjolnirShortcodeEventData>("org.matrix.mjolnir.shortcode");
-            roomInfo.Shortcode = shortcodeState.Shortcode;
-
-            if (roomInfo.Shortcode is not null) {
-                roomInfo.Name = await r.GetNameAsync();
-                return roomInfo;
-            }
-
-            return null;
-        }
-        finally {
-            checkedRoomCount++;
-            StateHasChanged();
-            semaphore.Release();
-        }
-    }
-
-    
-
-    public struct PolicyRoomInfo {
-        public
-            string RoomId { get; set; }
-
-        public
-            string? Shortcode { get; set; }
-
-        public
-            string? Name { get; set; }
-    }
-
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor
deleted file mode 100644
index 087adf8..0000000
--- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManager.razor
+++ /dev/null
@@ -1,96 +0,0 @@
-@page "/RoomManager"
-@inject ILocalStorageService LocalStorage
-@inject NavigationManager NavigationManager
-<h3>Room manager</h3>
-<hr/>
-@if (Rooms.Count == 0) {
-    <p>You are not in any rooms!</p>
-}
-else {
-    <p>You are in @Rooms.Count rooms and @Spaces.Count spaces</p>
-    <p>
-        <a href="/RoomManagerCreateRoom">Create room</a>
-    </p>
-
-    <details open>
-        <summary>Space List</summary>
-        @foreach (var room in Spaces) {
-            <a style="color: unset; text-decoration: unset;" href="/RoomManager/Space/@room.RoomId.Replace('.', '~')">
-                <RoomListItem Room="@room" ShowOwnProfile="false"></RoomListItem>
-            </a>
-        }
-    </details>
-    <details open>
-        <summary>Room List</summary>
-        @foreach (var room in Rooms) {
-            <a style="color: unset; text-decoration: unset;" href="/RoomManager/Room/@room.RoomId.Replace('.', '~')">
-                <RoomListItem Room="@room" ShowOwnProfile="true"></RoomListItem>
-            </a>
-        }
-    </details>
-}
-
-<div style="margin-bottom: 4em;"></div>
-<LogView></LogView>
-
-@code {
-    public List<GenericRoom> Rooms { get; set; } = new();
-    public List<GenericRoom> Spaces { get; set; } = new();
-
-    protected override async Task OnInitializedAsync() {
-        Console.WriteLine("Initializing room manager");
-        Console.WriteLine("Loaded from local storage");
-        await base.OnInitializedAsync();
-        Console.WriteLine("Initialized base");
-        var hs = await MRUStorage.GetCurrentSessionOrNavigate();
-        if (hs is null) return;
-        Console.WriteLine("Fetching joined rooms");
-        var _rooms = await hs.GetJoinedRooms();
-        StateHasChanged();
-        Console.WriteLine($"Got {_rooms.Count} rooms");
-        var semaphore = new SemaphoreSlim(10);
-        var tasks = new List<Task<GenericRoom?>>();
-        foreach (var room in _rooms) {
-            tasks.Add(CheckIfSpace(room, semaphore));
-        }
-        await Task.WhenAll(tasks);
-
-        Console.WriteLine("Fetched joined rooms!");
-    }
-
-    private async Task<GenericRoom?> CheckIfSpace(GenericRoom room, SemaphoreSlim semaphore) {
-        await semaphore.WaitAsync();
-    // Console.WriteLine($"Checking if {room.RoomId} is a space");
-        try {
-            var state = await room.GetStateAsync<CreateEvent>("m.room.create");
-            if (state is not null) {
-    //Console.WriteLine(state.Value.ToJson());
-                if (state.Type is not null) {
-                    if (state.Type == "m.space") {
-                        Console.WriteLine($"Room {room.RoomId} is a space!");
-                        Spaces.Add(room);
-                        StateHasChanged();
-                        return room;
-                    }
-                    else {
-                        Console.WriteLine($"Encountered unknown room type {state.Type}");
-                    }
-                }
-                else {
-                    Rooms.Add(room);
-    //this is fine, apprently...
-    // Console.WriteLine($"Room {room.RoomId} has no Content.type in m.room.create!");
-                }
-            }
-        }
-        catch (Exception e) {
-            Console.WriteLine(e);
-            return null;
-        }
-        finally {
-            semaphore.Release();
-        }
-        return null;
-    }
-
-}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor
index e32b5cb..3225c15 100644
--- a/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor
+++ b/MatrixRoomUtils.Web/Pages/RoomManager/RoomManagerTimeline.razor
@@ -14,13 +14,12 @@
 @code {
 
     [Parameter]
-    public string RoomId { get; set; } = "invalid!!!!!!";
+    public string RoomId { get; set; }
 
     private List<MessagesResponse> Messages { get; } = new();
     private List<StateEventResponse> Events { get; } = new();
 
     protected override async Task OnInitializedAsync() {
-        RoomId = RoomId.Replace('~', '.');
         Console.WriteLine("RoomId: " + RoomId);
         var hs = await MRUStorage.GetCurrentSessionOrNavigate();
         if (hs is null) return;
@@ -46,10 +45,10 @@
         _ => typeof(TimelineUnknownItem)
         };
 
-    private Dictionary<string, object> ComponentParameters(Type ComponentType, StateEventResponse Event) => ComponentType switch {
-        Type t when t == typeof(TimelineMessageItem) => new Dictionary<string, object> { { "Event", Event }, { "Events", Events } },
-        Type t when t == typeof(TimelineMemberItem) => new Dictionary<string, object> { { "Event", Event }, { "Events", Events } },
-        _ => new Dictionary<string, object> { { "Event", Event }, { "Events", Events } }
+    private Dictionary<string, object> ComponentParameters(Type componentType, StateEventResponse @event) => componentType switch {
+        not null when componentType == typeof(TimelineMessageItem) => new Dictionary<string, object> { { "Event", @event }, { "Events", Events } },
+        not null when componentType == typeof(TimelineMemberItem) => new Dictionary<string, object> { { "Event", @event }, { "Events", Events } },
+        _ => new Dictionary<string, object> { { "Event", @event }, { "Events", Events } }
         };
 
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
index 932748d..d88d5b2 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
@@ -1,5 +1,6 @@
 @page "/Rooms"
 @using MatrixRoomUtils.Core.StateEventTypes
+@using MatrixRoomUtils.Core.StateEventTypes.Spec
 <h3>Room list</h3>
 
 @if (Rooms is not null) {
@@ -9,14 +10,14 @@
 
 @code {
 
-    private List<GenericRoom> Rooms { get; set; }
-    private ProfileResponse GlobalProfile { get; set; }
-    
+    private List<RoomInfo> Rooms { get; set; }
+    private ProfileResponseEventData GlobalProfile { get; set; }
+
     protected override async Task OnInitializedAsync() {
         var hs = await MRUStorage.GetCurrentSessionOrNavigate();
         if (hs is null) return;
         GlobalProfile = await hs.GetProfile(hs.WhoAmI.UserId);
-        Rooms = await hs.GetJoinedRooms();
+        Rooms = (await hs.GetJoinedRooms()).Select(x => new RoomInfo() { Room = x }).ToList();
 
         await base.OnInitializedAsync();
     }
diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor
index 8e2609f..4cb16b8 100644
--- a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor
@@ -1,8 +1,9 @@
-@page "/PolicyListEditor/{RoomId}"
+@page "/Rooms/{RoomId}/Policies"
 @using MatrixRoomUtils.Core.StateEventTypes
 @using System.Text.Json
 @using MatrixRoomUtils.Core.Helpers
 @using MatrixRoomUtils.Core.Responses
+@using MatrixRoomUtils.Core.StateEventTypes.Spec
 <h3>Policy list editor - Editing @RoomId</h3>
 <hr/>
 
diff --git a/MatrixRoomUtils.Web/Shared/InlineUserItem.razor b/MatrixRoomUtils.Web/Shared/InlineUserItem.razor
index a498c70..ffccc25 100644
--- a/MatrixRoomUtils.Web/Shared/InlineUserItem.razor
+++ b/MatrixRoomUtils.Web/Shared/InlineUserItem.razor
@@ -1,6 +1,7 @@
 @using MatrixRoomUtils.Core.Responses
 @using MatrixRoomUtils.Core.StateEventTypes
 @using MatrixRoomUtils.Core.Helpers
+@using MatrixRoomUtils.Core.StateEventTypes.Spec
 <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>
@@ -19,7 +20,7 @@
     public RenderFragment? ChildContent { get; set; }
 
     [Parameter]
-    public ProfileResponse User { get; set; }
+    public ProfileResponseEventData User { get; set; }
 
     [Parameter]
     public string? UserId { get; set; }
diff --git a/MatrixRoomUtils.Web/Shared/RoomList.razor b/MatrixRoomUtils.Web/Shared/RoomList.razor
index 7e002ed..db2d059 100644
--- a/MatrixRoomUtils.Web/Shared/RoomList.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomList.razor
@@ -1,5 +1,7 @@
 @using MatrixRoomUtils.Web.Shared.RoomListComponents;
 @using MatrixRoomUtils.Core.StateEventTypes
+@using MatrixRoomUtils.Core.StateEventTypes.Common
+@using MatrixRoomUtils.Core.StateEventTypes.Spec
 <p>@Rooms.Count rooms total, @RoomsWithTypes.Sum(x=>x.Value.Count) fetched so far...</p>
 @if(Rooms.Count != RoomsWithTypes.Sum(x=>x.Value.Count)) {
     <p>Fetching more rooms...</p>
@@ -16,14 +18,14 @@ else {
 @code {
 
     [Parameter]
-    public List<GenericRoom> Rooms { get; set; }
+    public List<RoomInfo> Rooms { get; set; }
     [Parameter]
-    public ProfileResponse? GlobalProfile { get; set; }
+    public ProfileResponseEventData? GlobalProfile { get; set; }
 
-    Dictionary<string, List<GenericRoom>> RoomsWithTypes = new();
+    Dictionary<string, List<RoomInfo>> RoomsWithTypes = new();
     
     protected override async Task OnInitializedAsync() {
-        GlobalProfile ??= await (await MRUStorage.GetCurrentSession()!).GetProfile((await MRUStorage.GetCurrentSession()!).WhoAmI.UserId);
+        GlobalProfile ??= await (await MRUStorage.GetCurrentSession())!.GetProfile((await MRUStorage.GetCurrentSession())!.WhoAmI.UserId);
         if (RoomsWithTypes.Any()) return;
 
         var tasks = Rooms.Select(AddRoom);
@@ -35,35 +37,42 @@ else {
     private string GetRoomTypeName(string? roomType) => roomType switch {
         "m.space" => "Space",
         "msc3588.stories.stories-room" => "Story room",
+        "support.feline.policy.lists.msc.v1" => "MSC3784 Policy list (v1)",
         null => "Room",
         _ => roomType
         };
 
     
-    private static SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(4, 4);
-    private async Task AddRoom(GenericRoom room) {
+    private static SemaphoreSlim _semaphoreSlim = new(8, 8);
+    private async Task AddRoom(RoomInfo room) {
         await _semaphoreSlim.WaitAsync();
         string roomType;
         try {
-            var createEvent = await room.GetCreateEventAsync();
+            RoomCreateEventData createEvent = (await room.GetStateEvent("m.room.create")).TypedContent as RoomCreateEventData;
             roomType = GetRoomTypeName(createEvent.Type);
 
             if (roomType == "Room") {
-                var shortcodeState = await room.GetStateAsync<MjolnirShortcodeEventData>("org.matrix.mjolnir.shortcode");
-                if (shortcodeState is not null) roomType = "Legacy policy room";
+                var mjolnirData = await room.GetStateEvent("org.matrix.mjolnir.shortcode");
+                if(mjolnirData?.RawContent?.ToJson(ignoreNull: true) is not null and not "{}")
+                    roomType = "Legacy policy room";
             }
+            //prefetch some stuff
+            await Task.WhenAll(
+                room.GetStateEvent("m.room.name"),
+                room.GetStateEvent("m.room.name")
+                );
         }
         catch (MatrixException e) {
             roomType = $"Error: {e.ErrorCode}";
         }
         
         if (!RoomsWithTypes.ContainsKey(roomType)) {
-            RoomsWithTypes.Add(roomType, new List<GenericRoom>());
+            RoomsWithTypes.Add(roomType, new List<RoomInfo>());
         }
         RoomsWithTypes[roomType].Add(room);
         
-    // if (RoomsWithTypes.Count % 10 == 0)
-        StateHasChanged();
+        // if (RoomsWithTypes[roomType].Count % 10 == 0)
+            StateHasChanged();
         // await Task.Delay(100);
         _semaphoreSlim.Release();
     }
diff --git a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
index e860321..4be3c1f 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListCategory.razor
@@ -1,12 +1,16 @@
 @using MatrixRoomUtils.Core.StateEventTypes
+@using MatrixRoomUtils.Core.StateEventTypes.Spec
 <details>
     <summary>@roomType (@rooms.Count)</summary>
     @foreach (var room in rooms) {
         <div class="room-list-item">
-            <RoomListItem Room="@room" ShowOwnProfile="@(roomType == "Room")"></RoomListItem>
-            <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.RoomId}/Timeline")">View timeline</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
-            <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.RoomId}/State/View")">View state</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
-            <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.RoomId}/State/Edit")">Edit state</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
+            <RoomListItem RoomInfo="@room" ShowOwnProfile="@(roomType == "Room")"></RoomListItem>
+            @if (room.StateEvents.Any(x => x.Type == "m.room.create")) {
+                
+            }
+            <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.Room.RoomId}/Timeline")">View timeline</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
+            <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.Room.RoomId}/State/View")">View state</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
+            <MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton href="@($"/Rooms/{room.Room.RoomId}/State/Edit")">Edit state</MatrixRoomUtils.Web.Shared.SimpleComponents.LinkButton>
             
             @if (roomType == "Space") {
                 <RoomListSpace Space="@room"></RoomListSpace>
@@ -19,12 +23,12 @@
 @code {
 
     [Parameter]
-    public KeyValuePair<string, List<GenericRoom>> Category { get; set; }
+    public KeyValuePair<string, List<RoomInfo>> Category { get; set; }
     
     [Parameter]
-    public ProfileResponse? GlobalProfile { get; set; }
+    public ProfileResponseEventData? GlobalProfile { get; set; }
 
     private string roomType => Category.Key;
-    private List<GenericRoom> rooms => Category.Value;
+    private List<RoomInfo> rooms => Category.Value;
     
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor
index 73dc334..5153658 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListComponents/RoomListSpace.razor
@@ -1,4 +1,4 @@
-<LinkButton href="@($"/Rooms/{Space.RoomId}/Space")">Manage space</LinkButton>
+<LinkButton href="@($"/Rooms/{Space.Room.RoomId}/Space")">Manage space</LinkButton>
 
 <br/>
 <details @ontoggle="SpaceChildrenOpened">
@@ -14,23 +14,25 @@
 @code {
 
     [Parameter]
-    public GenericRoom Space { get; set; }
+    public RoomInfo Space { get; set; }
 
     [Parameter, CascadingParameter]
     public string? Breadcrumbs {
-        get => _breadcrumbs + Space.RoomId;
+        get => _breadcrumbs + Space.Room.RoomId;
         set => _breadcrumbs = value;
     }
 
-    private List<GenericRoom> Children { get; set; } = new();
+    private List<RoomInfo> Children { get; set; } = new();
 
     protected override async Task OnInitializedAsync() {
         if (Breadcrumbs == null) throw new ArgumentNullException(nameof(Breadcrumbs));
         await Task.Delay(Random.Shared.Next(1000, 10000));
-        var rooms = Space.AsSpace.GetRoomsAsync();
+        var rooms = Space.Room.AsSpace.GetRoomsAsync();
         await foreach (var room in rooms) {
-            if(Breadcrumbs.Contains(room.RoomId)) continue;
-            Children.Add(room);
+            if (Breadcrumbs.Contains(room.RoomId)) continue;
+            Children.Add(new() {
+                Room = room
+            });
         }
         await base.OnInitializedAsync();
     }
@@ -41,7 +43,7 @@
     private async Task SpaceChildrenOpened() {
         if (_shouldRenderChildren) return;
         _shouldRenderChildren = true;
-        Console.WriteLine($"[RoomList] Rendering children of {Space.RoomId}");
+        Console.WriteLine($"[RoomList] Rendering children of {Space.Room.RoomId}");
     }
 
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
index 13cc02d..d35c9ab 100644
--- a/MatrixRoomUtils.Web/Shared/RoomListItem.razor
+++ b/MatrixRoomUtils.Web/Shared/RoomListItem.razor
@@ -2,6 +2,7 @@
 @using System.Text.Json
 @using MatrixRoomUtils.Core.Helpers
 @using MatrixRoomUtils.Core.StateEventTypes
+@using MatrixRoomUtils.Core.StateEventTypes.Spec
 <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) {
         <img class="imageUnloaded @(string.IsNullOrWhiteSpace(OwnMemberState?.AvatarUrl ?? GlobalProfile?.AvatarUrl) ? "" : "imageLoaded")"
@@ -30,6 +31,9 @@
 
     [Parameter]
     public GenericRoom? Room { get; set; }
+    
+    [Parameter]
+    public RoomInfo? RoomInfo { get; set; }
 
     [Parameter]
     public string? RoomId { get; set; }
@@ -40,8 +44,8 @@
     [Parameter]
     public RoomMemberEventData? OwnMemberState { get; set; }
 
-    [Parameter]
-    public ProfileResponse? GlobalProfile { get; set; }
+    [CascadingParameter]
+    public ProfileResponseEventData? GlobalProfile { get; set; }
 
     private string? roomName { get; set; }
 
@@ -62,11 +66,19 @@
         hs ??= await MRUStorage.GetCurrentSessionOrNavigate();
         if (hs is null) return;
 
-        if (Room is null && RoomId is null) {
+        if (Room is null && RoomId is null && RoomInfo is null) {
             throw new ArgumentNullException(nameof(RoomId));
         }
-        Room ??= await hs.GetRoom(RoomId);
-        RoomId = Room.RoomId;
+        
+        // sweep from roominfo to id
+        if (RoomInfo is not null) Room = RoomInfo.Room;
+        if(Room is not null) RoomId = Room.RoomId;
+        
+        //sweep from id to roominfo
+        if(RoomId is not null) Room ??= await hs.GetRoom(RoomId);
+        if(Room is not null) RoomInfo ??= new RoomInfo() {
+            Room = Room
+        };
 
         await CheckRoomVersion();
         await GetRoomInfo();
@@ -77,8 +89,8 @@
     private async Task LoadOwnProfile() {
         if (!ShowOwnProfile) return;
         try {
-            OwnMemberState ??= await Room.GetStateAsync<RoomMemberEventData>("m.room.member", hs.UserId);
-            GlobalProfile ??= await hs.GetProfile(hs.UserId, true);
+            OwnMemberState ??= (await RoomInfo.GetStateEvent("m.room.member", hs.UserId)).TypedContent as RoomMemberEventData;
+            GlobalProfile ??= await hs.GetProfile(hs.UserId);
         }
         catch (MatrixException e) {
             if (e is { ErrorCode: "M_FORBIDDEN" }) {
@@ -93,7 +105,7 @@
 
     private async Task CheckRoomVersion() {
         try {
-            var ce = await Room.GetCreateEventAsync();
+            var ce = (await RoomInfo.GetStateEvent("m.room.create")).TypedContent as RoomCreateEventData;
             if (int.TryParse(ce.RoomVersion, out var rv)) {
                 if (rv < 10)
                     hasOldRoomVersion = true;
@@ -115,9 +127,9 @@
 
     private async Task GetRoomInfo() {
         try {
-            roomName ??= await Room.GetNameAsync();
+            roomName ??= ((await RoomInfo.GetStateEvent("m.room.name"))?.TypedContent as RoomNameEventData)?.Name ?? RoomId;
 
-            var state = await Room.GetStateAsync<RoomAvatarEventData>("m.room.avatar");
+            var state = (await RoomInfo.GetStateEvent("m.room.avatar")).TypedContent as RoomAvatarEventData;
             if (state?.Url is { } url) {
                 roomIcon = MediaResolver.ResolveMediaUri(hs.FullHomeServerDomain, url);
                 Console.WriteLine($"Got avatar for room {RoomId}: {roomIcon} ({url})");
diff --git a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor
index b7e0220..519e0b2 100644
--- a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor
+++ b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor
@@ -1,5 +1,6 @@
 @using MatrixRoomUtils.Core.Responses
 @using MatrixRoomUtils.Core.StateEventTypes
+@using MatrixRoomUtils.Core.StateEventTypes.Spec
 
 @if (roomMemberData.Membership == "ban") {
     <i>@Event.StateKey was banned</i>
diff --git a/MatrixRoomUtils.Web/Shared/UserListItem.razor b/MatrixRoomUtils.Web/Shared/UserListItem.razor
index a41ce49..20b1c8c 100644
--- a/MatrixRoomUtils.Web/Shared/UserListItem.razor
+++ b/MatrixRoomUtils.Web/Shared/UserListItem.razor
@@ -1,6 +1,7 @@
 @using MatrixRoomUtils.Core.Responses
 @using MatrixRoomUtils.Core.StateEventTypes
 @using MatrixRoomUtils.Core.Helpers
+@using MatrixRoomUtils.Core.StateEventTypes.Spec
 <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>
@@ -19,7 +20,7 @@
     public RenderFragment? ChildContent { get; set; }
 
     [Parameter]
-    public ProfileResponse User { get; set; }
+    public ProfileResponseEventData User { get; set; }
 
     [Parameter]
     public string UserId { get; set; }