Commit Graph
56 Commits
Author SHA1 Message Date
theS1LV3R 5b5ba53980 fix: Fix merge problems, update to resolvematrix 0.1.0 2026-07-03 10:59:12 +02:00
theS1LV3R 3d521c8898 feat: Add cache clearing
diff --git c/Cargo.lock i/Cargo.lock
index 4a8b1e273..239932c62 100644
--- c/Cargo.lock
+++ i/Cargo.lock
@@ -4601,9 +4601,9 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"

 [[package]]
 name = "resolvematrix"
-version = "0.0.3"
+version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52dfcc6f56a81348db1fc6591356cfea9dc840408c75553b2fe225f86de43274"
+checksum = "ea2b9bc3cb1220455bf50519f315c27257859059cb1b0f1643758afd03cbef8a"
 dependencies = [
  "hickory-resolver",
  "reqwest 0.13.2",
diff --git c/Cargo.toml i/Cargo.toml
index f89a5e010..d6260177a 100644
--- c/Cargo.toml
+++ i/Cargo.toml
@@ -45,7 +45,7 @@ version = "1.0.6"
 version = "1.0.0"

 [workspace.dependencies.cargo_toml]
-version = "1.0"
+version = "0.22"
 default-features = false
 features = ["features"]

@@ -164,7 +164,7 @@ features = ["raw_value"]

 # Used for appservice registration files
 [workspace.dependencies.serde-saphyr]
-version = "0.0.28"
+version = "0.0.27"

 # Used to load forbidden room/user regex from config
 [workspace.dependencies.serde_regex]
@@ -356,7 +356,6 @@ features = [
     "ring-compat",
     "compat-upload-signatures",
     "compat-optional-txn-pdus",
-    "compat-get-3pids",
     "unstable-msc2666",
     "unstable-msc2867",
     "unstable-msc2870",
@@ -561,10 +560,7 @@ features = ["std"]
 version = "0.3.0"

 [workspace.dependencies.resolvematrix]
-version = "0.1.0"
-
-[workspace.dependencies.serde_urlencoded]
-version = "0.7.1"
+version = "0.0.4"

 #
 # Patches
diff --git c/src/admin/query/resolver.rs i/src/admin/query/resolver.rs
index 4a88650f8..add4c70de 100644
--- c/src/admin/query/resolver.rs
+++ i/src/admin/query/resolver.rs
@@ -92,9 +92,11 @@ async fn overrides_cache(&self, server_name: Option<String>) -> Result {

 	async fn flush_cache(&self, name: Option<OwnedServerName>, all: bool) -> Result {
 		if all {
-			self.services.resolver.dns.cache.clear().await;
-			writeln!(self, "Resolver caches cleared!").await
-		} else if let Some(name) = name {
+		    self.services.resolver.resolver.clear_cache();
+		    self.services.resolver.dns.cache.clear().await;
+		    writeln!(self, "Resolver caches cleared!").await
+	    } else if let Some(name) = name {
+		    self.services.resolver.resolver.remove_cache_entry(&name.as_str());
 			self.services.resolver.dns.cache.del_destination(&name);
 			self.services.resolver.dns.cache.del_override(&name);
 			self.write_str(&format!("Cleared {name} from resolver caches!"))
diff --git c/src/service/resolver/mod.rs i/src/service/resolver/mod.rs
index c24b8ba60..6b57013dd 100644
--- c/src/service/resolver/mod.rs
+++ i/src/service/resolver/mod.rs
@@ -45,7 +45,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 	}

 	async fn clear_cache(&self) {
-		// No ability to clean resolvematrix cache at the moment
+		self.resolver.clear_cache();
 		self.dns.resolver.clear_cache();
 		self.dns.cache.clear().await;
 	}
2026-07-03 10:59:11 +02:00
theS1LV3R b5cd069d85 refactor: Rewrite resolver with resolvematrix
diff --git c/Cargo.lock i/Cargo.lock
index 081dc19e7..5b6b6fe4e 100644
--- c/Cargo.lock
+++ i/Cargo.lock
@@ -39,6 +39,24 @@ dependencies = [
  "memchr",
 ]

+[[package]]
+name = "aligned"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
+dependencies = [
+ "as-slice",
+]
+
+[[package]]
+name = "aligned-vec"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
+dependencies = [
+ "equator",
+]
+
 [[package]]
 name = "alloc-no-stdlib"
 version = "2.0.4"
@@ -47,9 +65,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"

 [[package]]
 name = "alloc-stdlib"
-version = "0.2.4"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
+checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
 dependencies = [
  "alloc-no-stdlib",
 ]
@@ -71,9 +89,9 @@ dependencies = [

 [[package]]
 name = "annotate-snippets"
-version = "0.12.16"
+version = "0.12.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f211a51805bc641f3ad5b7664c77d2547af685cc33b4cd8d31964027a46f13f1"
+checksum = "74fc7650eedcb2fee505aad48491529e408f0e854c2d9f63eb86c1361b9b3f93"
 dependencies = [
  "anstyle",
  "memchr",
@@ -102,14 +120,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"

 [[package]]
-name = "arc-swap"
-version = "1.9.1"
+name = "ar_archive_writer"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207"
+checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b"
+dependencies = [
+ "object",
+]
+
+[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+
+[[package]]
+name = "arc-swap"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5"
 dependencies = [
  "rustversion",
 ]

+[[package]]
+name = "arg_enum_proc_macro"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "argon2"
 version = "0.5.3"
@@ -137,6 +181,15 @@ dependencies = [
  "serde",
 ]

+[[package]]
+name = "as-slice"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
+dependencies = [
+ "stable_deref_trait",
+]
+
 [[package]]
 name = "as_variant"
 version = "1.3.0"
@@ -145,9 +198,9 @@ checksum = "9dbc3a507a82b17ba0d98f6ce8fd6954ea0c8152e98009d36a40d8dcc8ce078a"

 [[package]]
 name = "askama"
-version = "0.16.0"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bf825125edd887a019d0a3a837dcc5499a68b0d034cc3eb594070c3e18addc"
+checksum = "08e1676b346cadfec169374f949d7490fd80a24193d37d2afce0c047cf695e57"
 dependencies = [
  "askama_macros",
  "itoa",
@@ -158,13 +211,12 @@ dependencies = [

 [[package]]
 name = "askama_derive"
-version = "0.16.0"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1c7065972a130eafa84215f21352ae15b4a7393da48c1f5e103904490736738"
+checksum = "7661ff56517787343f376f75db037426facd7c8d3049cef8911f1e75016f3a37"
 dependencies = [
  "askama_parser",
  "basic-toml",
- "glob",
  "memchr",
  "proc-macro2",
  "quote",
@@ -176,24 +228,63 @@ dependencies = [

 [[package]]
 name = "askama_macros"
-version = "0.16.0"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e23b1d2c4bd39a41971f6124cef4cc6fd0540913ecb90919b69ab3bbe44ae1a"
+checksum = "713ee4dbfd1eb719c2dab859465b01fa1d21cb566684614a713a6b7a99a4e47b"
 dependencies = [
  "askama_derive",
 ]

 [[package]]
 name = "askama_parser"
-version = "0.16.0"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7db09fde9143e7ac4513358fb32ee32847125b63b18ea715afd487956da715da"
+checksum = "1d62d674238a526418b30c0def480d5beadb9d8964e7f38d635b03bf639c704c"
 dependencies = [
  "rustc-hash",
  "serde",
  "serde_derive",
  "unicode-ident",
- "winnow 1.0.3",
+ "winnow 0.7.15",
+]
+
+[[package]]
+name = "asn1-rs"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60"
+dependencies = [
+ "asn1-rs-derive",
+ "asn1-rs-impl",
+ "displaydoc",
+ "nom 7.1.3",
+ "num-traits",
+ "rusticata-macros",
+ "thiserror 2.0.18",
+ "time",
+]
+
+[[package]]
+name = "asn1-rs-derive"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "asn1-rs-impl"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]

 [[package]]
@@ -215,9 +306,9 @@ dependencies = [

 [[package]]
 name = "async-compression"
-version = "0.4.42"
+version = "0.4.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac"
+checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1"
 dependencies = [
  "compression-codecs",
  "compression-core",
@@ -253,15 +344,58 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"

 [[package]]
 name = "autocfg"
-version = "1.5.1"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "av-scenechange"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
+dependencies = [
+ "aligned",
+ "anyhow",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "log",
+ "num-rational",
+ "num-traits",
+ "pastey",
+ "rayon",
+ "thiserror 2.0.18",
+ "v_frame",
+ "y4m",
+]
+
+[[package]]
+name = "av1-grain"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
+dependencies = [
+ "anyhow",
+ "arrayvec",
+ "log",
+ "nom 8.0.0",
+ "num-rational",
+ "v_frame",
+]
+
+[[package]]
+name = "avif-serialize"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
+dependencies = [
+ "arrayvec",
+]

 [[package]]
 name = "aws-lc-rs"
-version = "1.17.0"
+version = "1.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00"
+checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf"
 dependencies = [
  "aws-lc-sys",
  "zeroize",
@@ -269,9 +403,9 @@ dependencies = [

 [[package]]
 name = "aws-lc-sys"
-version = "0.41.0"
+version = "0.38.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4"
+checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e"
 dependencies = [
  "cc",
  "cmake",
@@ -281,9 +415,9 @@ dependencies = [

 [[package]]
 name = "axum"
-version = "0.8.9"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90"
+checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
 dependencies = [
  "axum-core",
  "bytes",
@@ -314,12 +448,12 @@ dependencies = [

 [[package]]
 name = "axum-client-ip"
-version = "1.3.1"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8ba1af5b620232acf37f2eb6d22151ea465491e0b4c25f552d1990f64ec5a67"
+checksum = "dff8ee1869817523c8f91c20bf17fd932707f66c2e7e0b0f811b29a227289562"
 dependencies = [
  "axum",
- "client-ip",
+ "forwarded-header-value",
  "serde",
 ]

@@ -344,9 +478,9 @@ dependencies = [

 [[package]]
 name = "axum-extra"
-version = "0.12.6"
+version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970"
+checksum = "fef252edff26ddba56bbcdf2ee3307b8129acb86f5749b68990c168a6fcc9c76"
 dependencies = [
  "axum",
  "axum-core",
@@ -367,13 +501,12 @@ dependencies = [

 [[package]]
 name = "axum-server"
-version = "0.8.0"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1df331683d982a0b9492b38127151e6453639cd34926eb9c07d4cd8c6d22bfc"
+checksum = "c1ab4a3ec9ea8a657c72d99a03a824af695bd0fb5ec639ccbd9cd3543b41a5f9"
 dependencies = [
  "arc-swap",
  "bytes",
- "either",
  "fs-err",
  "http",
  "http-body",
@@ -381,6 +514,7 @@ dependencies = [
  "hyper-util",
  "pin-project-lite",
  "rustls",
+ "rustls-pemfile",
  "rustls-pki-types",
  "tokio",
  "tokio-rustls",
@@ -389,8 +523,9 @@ dependencies = [

 [[package]]
 name = "axum-server-dual-protocol"
-version = "0.8.0"
-source = "git+https://github.com/vinchona/axum-server-dual-protocol.git?rev=ca6db055254255b74238673ce4135698e347d71c#ca6db055254255b74238673ce4135698e347d71c"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2164551db024e87f20316d164eab9f5ad342d8188b08051ceb15ca92a60ea7b7"
 dependencies = [
  "axum-server",
  "bytes",
@@ -461,15 +596,30 @@ dependencies = [
  "quote",
  "regex",
  "rustc-hash",
- "shlex 1.3.0",
+ "shlex",
  "syn",
 ]

 [[package]]
-name = "bitflags"
-version = "2.13.0"
+name = "bit_field"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
+checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
+
+[[package]]
+name = "bitflags"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
+
+[[package]]
+name = "bitstream-io"
+version = "4.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757"
+dependencies = [
+ "core2",
+]

 [[package]]
 name = "blake2"
@@ -477,7 +627,7 @@ version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
 dependencies = [
- "digest 0.10.7",
+ "digest",
 ]

 [[package]]
@@ -489,15 +639,6 @@ dependencies = [
  "generic-array",
 ]

-[[package]]
-name = "block-buffer"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
-dependencies = [
- "hybrid-array",
-]
-
 [[package]]
 name = "block2"
 version = "0.6.2"
@@ -508,10 +649,19 @@ dependencies = [
 ]

 [[package]]
-name = "brotli"
-version = "8.0.4"
+name = "blurhash"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
+checksum = "e79769241dcd44edf79a732545e8b5cec84c247ac060f5252cd51885d093a8fc"
+dependencies = [
+ "image",
+]
+
+[[package]]
+name = "brotli"
+version = "8.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560"
 dependencies = [
  "alloc-no-stdlib",
  "alloc-stdlib",
@@ -520,9 +670,9 @@ dependencies = [

 [[package]]
 name = "brotli-decompressor"
-version = "5.0.3"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
+checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
 dependencies = [
  "alloc-no-stdlib",
  "alloc-stdlib",
@@ -530,15 +680,15 @@ dependencies = [

 [[package]]
 name = "built"
-version = "0.8.1"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9"
+checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"

 [[package]]
 name = "bumpalo"
-version = "3.20.3"
+version = "3.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"

 [[package]]
 name = "bytemuck"
@@ -560,15 +710,15 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"

 [[package]]
 name = "bytes"
-version = "1.12.0"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"

 [[package]]
 name = "bytesize"
-version = "2.4.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49e78e506b9d7633710dab98996f22f95f3d0f488e8f1aa162830556ed9fc14d"
+checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3"

 [[package]]
 name = "bzip2-sys"
@@ -591,9 +741,9 @@ dependencies = [

 [[package]]
 name = "cargo-platform"
-version = "0.3.3"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0061da739915fae12ea00e16397555ed4371a6bb285431aab930f61b0aa4ba"
+checksum = "87a0c0e6148f11f01f32650a2ea02d532b2ad4e81d8bd41e6e565b5adc5e6082"
 dependencies = [
  "serde",
  "serde_core",
@@ -610,7 +760,7 @@ dependencies = [
  "semver",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 2.0.18",
 ]

 [[package]]
@@ -625,16 +775,22 @@ dependencies = [

 [[package]]
 name = "cc"
-version = "1.2.64"
+version = "1.2.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
+checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
 dependencies = [
  "find-msvc-tools",
  "jobserver",
  "libc",
- "shlex 2.0.1",
+ "shlex",
 ]

+[[package]]
+name = "cesu8"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+
 [[package]]
 name = "cexpr"
 version = "0.6.0"
@@ -664,7 +820,7 @@ checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
 dependencies = [
  "cfg-if",
  "cpufeatures 0.3.0",
- "rand_core 0.10.1",
+ "rand_core 0.10.0",
 ]

 [[package]]
@@ -678,13 +834,23 @@ dependencies = [

 [[package]]
 name = "chrono"
-version = "0.4.45"
+version = "0.4.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
+checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
 dependencies = [
  "num-traits",
 ]

+[[package]]
+name = "chumsky"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9"
+dependencies = [
+ "hashbrown 0.14.5",
+ "stacker",
+]
+
 [[package]]
 name = "clang-sys"
 version = "1.8.1"
@@ -698,9 +864,9 @@ dependencies = [

 [[package]]
 name = "clap"
-version = "4.6.1"
+version = "4.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
+checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -718,9 +884,9 @@ dependencies = [

 [[package]]
 name = "clap_derive"
-version = "4.6.1"
+version = "4.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
+checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -734,30 +900,15 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"

-[[package]]
-name = "client-ip"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39d2056bf065c8b4bce5a8898d40e175211ff4410add2a84d695845d3937c729"
-dependencies = [
- "http",
-]
-
 [[package]]
 name = "cmake"
-version = "0.1.58"
+version = "0.1.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
+checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
 dependencies = [
  "cc",
 ]

-[[package]]
-name = "cmov"
-version = "0.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
-
 [[package]]
 name = "color_quant"
 version = "1.1.0"
@@ -776,9 +927,9 @@ dependencies = [

 [[package]]
 name = "compression-codecs"
-version = "0.4.38"
+version = "0.4.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf"
+checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7"
 dependencies = [
  "brotli",
  "compression-core",
@@ -790,9 +941,9 @@ dependencies = [

 [[package]]
 name = "compression-core"
-version = "0.4.32"
+version = "0.4.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789"
+checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d"

 [[package]]
 name = "concurrent-queue"
@@ -805,30 +956,24 @@ dependencies = [

 [[package]]
 name = "conduwuit"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
- "aws-lc-rs",
  "clap",
  "conduwuit_admin",
  "conduwuit_api",
  "conduwuit_build_metadata",
  "conduwuit_core",
  "conduwuit_database",
- "conduwuit_macros",
  "conduwuit_router",
  "conduwuit_service",
  "console-subscriber",
  "const-str",
- "ctor",
- "dtor",
  "hardened_malloc-rs",
  "log",
  "opentelemetry",
  "opentelemetry-otlp",
  "opentelemetry_sdk",
  "parking_lot",
- "reqwest 0.13.4",
- "rustls",
  "sentry",
  "sentry-tower",
  "sentry-tracing",
@@ -843,9 +988,8 @@ dependencies = [

 [[package]]
 name = "conduwuit_admin"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
- "assign",
  "clap",
  "conduwuit_api",
  "conduwuit_core",
@@ -853,11 +997,10 @@ dependencies = [
  "conduwuit_macros",
  "conduwuit_service",
  "const-str",
- "ctor",
- "dtor",
  "futures",
  "lettre",
  "log",
+ "resolvematrix",
  "ruma",
  "serde-saphyr",
  "serde_json",
@@ -868,9 +1011,8 @@ dependencies = [

 [[package]]
 name = "conduwuit_api"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
- "assign",
  "async-trait",
  "axum",
  "axum-client-ip",
@@ -878,47 +1020,41 @@ dependencies = [
  "base64 0.22.1",
  "bytes",
  "conduwuit_core",
- "conduwuit_macros",
  "conduwuit_service",
  "const-str",
- "ctor",
- "dtor",
  "futures",
  "hmac",
  "http",
  "http-body-util",
  "hyper",
  "ipaddress",
- "itertools 0.15.0",
+ "itertools 0.14.0",
  "lettre",
  "log",
- "rand 0.10.1",
- "reqwest 0.13.4",
+ "rand 0.10.0",
+ "reqwest 0.12.28",
  "ruma",
- "ruminuwuity",
  "serde",
  "serde_html_form",
  "serde_json",
- "sha1 0.11.0",
+ "sha1",
  "tokio",
  "tracing",
 ]

 [[package]]
 name = "conduwuit_build_metadata"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
  "built",
- "cargo_metadata",
 ]

 [[package]]
 name = "conduwuit_core"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
  "argon2",
  "arrayvec",
- "assign",
  "axum",
  "axum-extra",
  "bytes",
@@ -933,7 +1069,6 @@ dependencies = [
  "core_affinity",
  "ctor",
  "cyborgtime",
- "dtor",
  "either",
  "figment",
  "futures",
@@ -942,36 +1077,37 @@ dependencies = [
  "http-body-util",
  "hyper-util",
  "ipaddress",
- "itertools 0.15.0",
+ "itertools 0.14.0",
  "lettre",
  "libc",
  "libloading 0.9.0",
  "lock_api",
  "log",
  "maplit",
- "nix",
+ "nix 0.31.2",
  "num-traits",
  "parking_lot",
- "rand 0.10.1",
+ "rand 0.10.0",
  "rand_core 0.6.4",
  "regex",
- "reqwest 0.13.4",
+ "reqwest 0.12.28",
+ "resolvematrix",
+ "ring",
  "ruma",
  "sanitize-filename",
  "serde",
  "serde-saphyr",
  "serde_json",
  "serde_regex",
- "sha2 0.11.0",
  "smallstr",
  "smallvec",
- "thiserror",
+ "thiserror 2.0.18",
  "tikv-jemalloc-ctl",
  "tikv-jemalloc-sys",
  "tikv-jemallocator",
  "tokio",
  "tokio-metrics",
- "toml 1.1.2+spec-1.1.0",
+ "toml 0.9.12+spec-1.1.0",
  "tracing",
  "tracing-core",
  "tracing-subscriber",
@@ -980,14 +1116,11 @@ dependencies = [

 [[package]]
 name = "conduwuit_database"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
  "async-channel",
  "conduwuit_core",
- "conduwuit_macros",
  "const-str",
- "ctor",
- "dtor",
  "futures",
  "log",
  "minicbor",
@@ -1001,10 +1134,9 @@ dependencies = [

 [[package]]
 name = "conduwuit_macros"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
- "cargo_toml",
- "itertools 0.15.0",
+ "itertools 0.14.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -1012,9 +1144,8 @@ dependencies = [

 [[package]]
 name = "conduwuit_router"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
- "assign",
  "axum",
  "axum-client-ip",
  "axum-server",
@@ -1023,12 +1154,9 @@ dependencies = [
  "conduwuit_admin",
  "conduwuit_api",
  "conduwuit_core",
- "conduwuit_macros",
  "conduwuit_service",
  "conduwuit_web",
  "const-str",
- "ctor",
- "dtor",
  "futures",
  "http",
  "http-body-util",
@@ -1044,25 +1172,22 @@ dependencies = [
  "serde_json",
  "tokio",
  "tower",
- "tower-http 0.7.0",
+ "tower-http",
  "tracing",
 ]

 [[package]]
 name = "conduwuit_service"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
  "askama",
- "assign",
  "async-trait",
  "base64 0.22.1",
+ "blurhash",
  "bytes",
  "conduwuit_core",
  "conduwuit_database",
- "conduwuit_macros",
  "const-str",
- "ctor",
- "dtor",
  "either",
  "futures",
  "governor",
@@ -1070,25 +1195,25 @@ dependencies = [
  "http",
  "image",
  "ipaddress",
- "itertools 0.15.0",
+ "itertools 0.14.0",
+ "ldap3",
  "lettre",
  "log",
  "loole",
  "lru-cache",
  "nonzero_ext",
- "rand 0.10.1",
+ "rand 0.10.0",
  "recaptcha-verify",
  "regex",
  "reqwest 0.12.28",
- "reqwest 0.13.4",
+ "resolvematrix",
  "ruma",
- "ruminuwuity",
  "rustyline-async",
  "sd-notify",
  "serde",
  "serde-saphyr",
  "serde_json",
- "sha2 0.11.0",
+ "sha2",
  "termimad",
  "tokio",
  "tracing",
@@ -1099,10 +1224,9 @@ dependencies = [

 [[package]]
 name = "conduwuit_web"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
  "askama",
- "assign",
  "async-trait",
  "axum",
  "axum-extra",
@@ -1112,11 +1236,11 @@ dependencies = [
  "conduwuit_service",
  "futures",
  "memory-serve",
- "rand 0.10.1",
+ "rand 0.10.0",
  "ruma",
  "serde",
- "thiserror",
- "tower-http 0.7.0",
+ "thiserror 2.0.18",
+ "tower-http",
  "tower-sec-fetch",
  "tracing",
  "validator",
@@ -1170,9 +1294,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"

 [[package]]
 name = "const-str"
-version = "1.1.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18f12cc9948ed9604230cdddc7c86e270f9401ccbe3c2e98a4378c5e7632212f"
+checksum = "b0664d2867b4a32697dfe655557f5c3b187e9b605b38612a748e5ec99811d160"

 [[package]]
 name = "const_panic"
@@ -1183,6 +1307,16 @@ dependencies = [
  "typewit",
 ]

+[[package]]
+name = "continuwuity-admin-api"
+version = "0.1.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
+dependencies = [
+ "ruma-common",
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "convert_case"
 version = "0.10.0"
@@ -1212,16 +1346,6 @@ dependencies = [
  "crossterm",
 ]

-[[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
 [[package]]
 name = "core-foundation"
 version = "0.10.1"
@@ -1238,6 +1362,15 @@ version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"

+[[package]]
+name = "core2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "core_affinity"
 version = "0.8.3"
@@ -1391,6 +1524,12 @@ dependencies = [
  "winapi",
 ]

+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
 [[package]]
 name = "crypto-common"
 version = "0.1.7"
@@ -1401,33 +1540,21 @@ dependencies = [
  "typenum",
 ]

-[[package]]
-name = "crypto-common"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
-dependencies = [
- "hybrid-array",
-]
-
 [[package]]
 name = "ctor"
-version = "1.0.7"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a"
+checksum = "424e0138278faeb2b401f174ad17e715c829512d74f3d1e81eb43365c2e0590e"
 dependencies = [
- "link-section",
- "linktime-proc-macro",
+ "ctor-proc-macro",
+ "dtor",
 ]

 [[package]]
-name = "ctutils"
-version = "0.4.2"
+name = "ctor-proc-macro"
+version = "0.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
-dependencies = [
- "cmov",
-]
+checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"

 [[package]]
 name = "curve25519-dalek"
@@ -1438,7 +1565,7 @@ dependencies = [
  "cfg-if",
  "cpufeatures 0.2.17",
  "curve25519-dalek-derive",
- "digest 0.10.7",
+ "digest",
  "fiat-crypto",
  "rustc_version",
  "subtle",
@@ -1499,9 +1626,9 @@ dependencies = [

 [[package]]
 name = "data-encoding"
-version = "2.11.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
+checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"

 [[package]]
 name = "date_header"
@@ -1529,11 +1656,28 @@ dependencies = [
  "zeroize",
 ]

+[[package]]
+name = "der-parser"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"
+dependencies = [
+ "asn1-rs",
+ "displaydoc",
+ "nom 7.1.3",
+ "num-bigint",
+ "num-traits",
+ "rusticata-macros",
+]
+
 [[package]]
 name = "deranged"
 version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+dependencies = [
+ "powerfmt",
+]

 [[package]]
 name = "derive_more"
@@ -1563,22 +1707,11 @@ version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
- "block-buffer 0.10.4",
- "crypto-common 0.1.7",
+ "block-buffer",
+ "crypto-common",
  "subtle",
 ]

-[[package]]
-name = "digest"
-version = "0.11.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
-dependencies = [
- "block-buffer 0.12.1",
- "crypto-common 0.2.2",
- "ctutils",
-]
-
 [[package]]
 name = "dispatch2"
 version = "0.3.1"
@@ -1591,9 +1724,9 @@ dependencies = [

 [[package]]
 name = "displaydoc"
-version = "0.2.6"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1610,14 +1743,30 @@ dependencies = [
 ]

 [[package]]
-name = "dtor"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d738e43aa64edab57c983d56de890d65fea7dc05605490c74451ce721dfd84b"
+name = "draupnir-antispam"
+version = "0.1.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
- "linktime-proc-macro",
+ "ruma-common",
+ "serde",
+ "serde_json",
 ]

+[[package]]
+name = "dtor"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301"
+dependencies = [
+ "dtor-proc-macro",
+]
+
+[[package]]
+name = "dtor-proc-macro"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
+
 [[package]]
 name = "dunce"
 version = "1.0.5"
@@ -1642,17 +1791,18 @@ checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
 dependencies = [
  "curve25519-dalek",
  "ed25519",
+ "rand_core 0.6.4",
  "serde",
- "sha2 0.10.9",
+ "sha2",
  "subtle",
  "zeroize",
 ]

 [[package]]
 name = "either"
-version = "1.16.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
 dependencies = [
  "serde",
 ]
@@ -1691,6 +1841,38 @@ dependencies = [
  "encoding_rs",
 ]

+[[package]]
+name = "enum-as-inner"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "equator"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
+dependencies = [
+ "equator-macro",
+]
+
+[[package]]
+name = "equator-macro"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "equivalent"
 version = "1.0.2"
@@ -1727,10 +1909,45 @@ dependencies = [
 ]

 [[package]]
-name = "fastrand"
-version = "2.4.1"
+name = "exr"
+version = "1.74.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
+checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
+dependencies = [
+ "bit_field",
+ "half",
+ "lebe",
+ "miniz_oxide",
+ "rayon-core",
+ "smallvec",
+ "zune-inflate",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "fax"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
+dependencies = [
+ "fax_derive",
+]
+
+[[package]]
+name = "fax_derive"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]

 [[package]]
 name = "fdeflate"
@@ -1822,6 +2039,16 @@ dependencies = [
  "percent-encoding",
 ]

+[[package]]
+name = "forwarded-header-value"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9"
+dependencies = [
+ "nonempty",
+ "thiserror 1.0.69",
+]
+
 [[package]]
 name = "fs-err"
 version = "3.3.0"
@@ -1921,9 +2148,9 @@ checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"

 [[package]]
 name = "futures-timer"
-version = "3.0.4"
+version = "3.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"

 [[package]]
 name = "futures-util"
@@ -1988,16 +2215,16 @@ dependencies = [
  "cfg-if",
  "libc",
  "r-efi 6.0.0",
- "rand_core 0.10.1",
+ "rand_core 0.10.0",
  "wasip2",
  "wasip3",
 ]

 [[package]]
 name = "gif"
-version = "0.14.2"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159"
+checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e"
 dependencies = [
  "color_quant",
  "weezl",
@@ -2034,21 +2261,11 @@ dependencies = [
  "web-time",
 ]

-[[package]]
-name = "granit-parser"
-version = "0.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f50ba32164f9e098d5da618776a32afbb32270adcbe3d3d006107dae11e37c91"
-dependencies = [
- "arraydeque",
- "smallvec",
-]
-
 [[package]]
 name = "h2"
-version = "0.4.15"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155"
+checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
 dependencies = [
  "atomic-waker",
  "bytes",
@@ -2091,12 +2308,33 @@ dependencies = [
  "tokio-util",
 ]

+[[package]]
+name = "half"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+ "zerocopy",
+]
+
 [[package]]
 name = "hardened_malloc-rs"
 version = "0.1.2+12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "647deb1583b14d160f85f3ff626f20b6edd366e3852c9843b06077388f794cb6"

+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+ "allocator-api2",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.15.5"
@@ -2117,12 +2355,6 @@ dependencies = [
  "foldhash 0.2.0",
 ]

-[[package]]
-name = "hashbrown"
-version = "0.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
-
 [[package]]
 name = "hdrhistogram"
 version = "7.5.4"
@@ -2148,7 +2380,7 @@ dependencies = [
  "http",
  "httpdate",
  "mime",
- "sha1 0.10.6",
+ "sha1",
 ]

 [[package]]
@@ -2179,84 +2411,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"

 [[package]]
-name = "hickory-net"
-version = "0.26.1"
+name = "hickory-proto"
+version = "0.25.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183"
+checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502"
 dependencies = [
  "async-trait",
  "cfg-if",
  "data-encoding",
+ "enum-as-inner",
  "futures-channel",
  "futures-io",
  "futures-util",
- "hickory-proto",
  "idna",
  "ipnet",
- "jni",
- "rand 0.10.1",
- "thiserror",
- "tinyvec",
- "tokio",
- "tracing",
- "url",
-]
-
-[[package]]
-name = "hickory-proto"
-version = "0.26.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bab31817bfb44672a252e97fe81cd0c18d1b2cf892108922f6818820df8c643"
-dependencies = [
- "data-encoding",
- "idna",
- "ipnet",
- "jni",
  "once_cell",
- "prefix-trie",
- "rand 0.10.1",
+ "rand 0.9.2",
  "ring",
  "serde",
- "thiserror",
+ "thiserror 2.0.18",
  "tinyvec",
+ "tokio",
  "tracing",
  "url",
 ]

 [[package]]
 name = "hickory-resolver"
-version = "0.26.1"
+version = "0.25.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c"
+checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a"
 dependencies = [
  "cfg-if",
  "futures-util",
- "hickory-net",
  "hickory-proto",
  "ipconfig",
- "ipnet",
- "jni",
  "moka",
- "ndk-context",
  "once_cell",
  "parking_lot",
- "rand 0.10.1",
+ "rand 0.9.2",
  "resolv-conf",
  "serde",
  "smallvec",
- "system-configuration",
- "thiserror",
+ "thiserror 2.0.18",
  "tokio",
  "tracing",
 ]

 [[package]]
 name = "hmac"
-version = "0.13.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.11.3",
+ "digest",
 ]

 [[package]]
@@ -2286,9 +2494,9 @@ dependencies = [

 [[package]]
 name = "http"
-version = "1.4.2"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
 dependencies = [
  "bytes",
  "itoa",
@@ -2344,20 +2552,11 @@ version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"

-[[package]]
-name = "hybrid-array"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da"
-dependencies = [
- "typenum",
-]
-
 [[package]]
 name = "hyper"
-version = "1.10.1"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498"
+checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
 dependencies = [
  "atomic-waker",
  "bytes",
@@ -2370,6 +2569,7 @@ dependencies = [
  "httpdate",
  "itoa",
  "pin-project-lite",
+ "pin-utils",
  "smallvec",
  "tokio",
  "want",
@@ -2377,18 +2577,20 @@ dependencies = [

 [[package]]
 name = "hyper-rustls"
-version = "0.27.9"
+version = "0.27.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
 dependencies = [
  "http",
  "hyper",
  "hyper-util",
  "rustls",
  "rustls-native-certs",
+ "rustls-pki-types",
  "tokio",
  "tokio-rustls",
  "tower-service",
+ "webpki-roots",
 ]

 [[package]]
@@ -2420,7 +2622,7 @@ dependencies = [
  "libc",
  "percent-encoding",
  "pin-project-lite",
- "socket2",
+ "socket2 0.6.3",
  "tokio",
  "tower-service",
  "tracing",
@@ -2428,13 +2630,12 @@ dependencies = [

 [[package]]
 name = "icu_collections"
-version = "2.2.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
+checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
 dependencies = [
  "displaydoc",
  "potential_utf",
- "utf8_iter",
  "yoke",
  "zerofrom",
  "zerovec",
@@ -2442,9 +2643,9 @@ dependencies = [

 [[package]]
 name = "icu_locale_core"
-version = "2.2.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
+checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
 dependencies = [
  "displaydoc",
  "litemap",
@@ -2455,9 +2656,9 @@ dependencies = [

 [[package]]
 name = "icu_normalizer"
-version = "2.2.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
+checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
 dependencies = [
  "icu_collections",
  "icu_normalizer_data",
@@ -2469,15 +2670,15 @@ dependencies = [

 [[package]]
 name = "icu_normalizer_data"
-version = "2.2.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
+checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"

 [[package]]
 name = "icu_properties"
-version = "2.2.0"
+version = "2.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
+checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
 dependencies = [
  "icu_collections",
  "icu_locale_core",
@@ -2489,15 +2690,15 @@ dependencies = [

 [[package]]
 name = "icu_properties_data"
-version = "2.2.0"
+version = "2.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
+checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"

 [[package]]
 name = "icu_provider"
-version = "2.2.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
+checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
 dependencies = [
  "displaydoc",
  "icu_locale_core",
@@ -2533,9 +2734,9 @@ dependencies = [

 [[package]]
 name = "idna_adapter"
-version = "1.2.2"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
 dependencies = [
  "icu_normalizer",
  "icu_properties",
@@ -2550,11 +2751,17 @@ dependencies = [
  "bytemuck",
  "byteorder-lite",
  "color_quant",
+ "exr",
  "gif",
  "image-webp",
  "moxcms",
  "num-traits",
  "png",
+ "qoi",
+ "ravif",
+ "rayon",
+ "rgb",
+ "tiff",
  "zune-core",
  "zune-jpeg",
 ]
@@ -2570,13 +2777,19 @@ dependencies = [
 ]

 [[package]]
-name = "indexmap"
-version = "2.14.0"
+name = "imgref"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
+
+[[package]]
+name = "indexmap"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
 dependencies = [
  "equivalent",
- "hashbrown 0.17.1",
+ "hashbrown 0.16.1",
  "serde",
  "serde_core",
 ]
@@ -2587,6 +2800,17 @@ version = "0.1.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"

+[[package]]
+name = "interpolate_name"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "ipaddress"
 version = "0.1.3"
@@ -2603,15 +2827,14 @@ dependencies = [

 [[package]]
 name = "ipconfig"
-version = "0.3.4"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222"
+checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
 dependencies = [
- "socket2",
+ "socket2 0.5.10",
  "widestring",
- "windows-registry",
- "windows-result",
- "windows-sys 0.61.2",
+ "windows-sys 0.48.0",
+ "winreg",
 ]

 [[package]]
@@ -2619,7 +2842,14 @@ name = "ipnet"
 version = "2.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
+
+[[package]]
+name = "iri-string"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
 dependencies = [
+ "memchr",
  "serde",
 ]

@@ -2641,49 +2871,35 @@ dependencies = [
  "either",
 ]

-[[package]]
-name = "itertools"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc"
-dependencies = [
- "either",
-]
-
 [[package]]
 name = "itoa"
-version = "1.0.18"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"

 [[package]]
 name = "jni"
-version = "0.22.4"
+version = "0.21.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
+checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
 dependencies = [
+ "cesu8",
  "cfg-if",
  "combine",
- "jni-macros",
- "jni-sys",
+ "jni-sys 0.3.1",
  "log",
- "simd_cesu8",
- "thiserror",
+ "thiserror 1.0.69",
  "walkdir",
- "windows-link",
+ "windows-sys 0.45.0",
 ]

 [[package]]
-name = "jni-macros"
-version = "0.22.4"
+name = "jni-sys"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
+checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258"
 dependencies = [
- "proc-macro2",
- "quote",
- "rustc_version",
- "simd_cesu8",
- "syn",
+ "jni-sys 0.4.1",
 ]

 [[package]]
@@ -2717,12 +2933,11 @@ dependencies = [

 [[package]]
 name = "js-sys"
-version = "0.3.102"
+version = "0.3.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
+checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
 dependencies = [
- "cfg-if",
- "futures-util",
+ "once_cell",
  "wasm-bindgen",
 ]

@@ -2737,20 +2952,30 @@ dependencies = [

 [[package]]
 name = "js_option"
-version = "0.2.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7dd3e281add16813cf673bf74a32249b0aa0d1c8117519a17b3ada5e8552b3c"
+checksum = "68421373957a1593a767013698dbf206e2b221eefe97a44d98d18672ff38423c"
 dependencies = [
- "serde_core",
+ "serde",
 ]

 [[package]]
 name = "konst"
-version = "0.4.3"
+version = "0.3.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f660d5f887e3562f9ab6f4a14988795b694099d66b4f5dedc02d197ba9becb1d"
+checksum = "4381b9b00c55f251f2ebe9473aef7c117e96828def1a7cb3bd3f0f903c6894e9"
 dependencies = [
  "const_panic",
+ "konst_kernel",
+ "typewit",
+]
+
+[[package]]
+name = "konst_kernel"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4b1eb7788f3824c629b1116a7a9060d6e898c358ebff59070093d51103dcc3c"
+dependencies = [
  "typewit",
 ]

@@ -2783,6 +3008,41 @@ version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"

+[[package]]
+name = "lber"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbcf559624bfd9fe8d488329a8959766335a43a9b8b2cdd6a2c379fca02909a5"
+dependencies = [
+ "bytes",
+ "nom 7.1.3",
+]
+
+[[package]]
+name = "ldap3"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01fe89f5e7cfb7e4701e3a38ff9f00358e026a9aee940355d88ee9d81e5c7503"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures",
+ "futures-util",
+ "lber",
+ "log",
+ "nom 7.1.3",
+ "percent-encoding",
+ "rustls",
+ "rustls-native-certs",
+ "thiserror 2.0.18",
+ "tokio",
+ "tokio-rustls",
+ "tokio-stream",
+ "tokio-util",
+ "url",
+ "x509-parser",
+]
+
 [[package]]
 name = "leb128fmt"
 version = "0.1.0"
@@ -2790,13 +3050,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"

 [[package]]
-name = "lettre"
-version = "0.11.22"
+name = "lebe"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0da65617f6cb926332d039cb578aad56178da86e128db6a1b09f4c94fa5b3349"
+checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
+
+[[package]]
+name = "lettre"
+version = "0.11.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e13e10e8818f8b2a60f52cb127041d388b89f3a96a62be9ceaffa22262fef7f"
 dependencies = [
  "async-trait",
  "base64 0.22.1",
+ "chumsky",
  "email-encoding",
  "email_address",
  "fastrand",
@@ -2812,7 +3079,7 @@ dependencies = [
  "rustls",
  "rustls-native-certs",
  "serde",
- "socket2",
+ "socket2 0.6.3",
  "tokio",
  "tokio-rustls",
  "tracing",
@@ -2821,9 +3088,19 @@ dependencies = [

 [[package]]
 name = "libc"
-version = "0.2.186"
+version = "0.2.183"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
+
+[[package]]
+name = "libfuzzer-sys"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
+dependencies = [
+ "arbitrary",
+ "cc",
+]

 [[package]]
 name = "libloading"
@@ -2847,33 +3124,21 @@ dependencies = [

 [[package]]
 name = "libz-sys"
-version = "1.1.29"
+version = "1.1.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9"
+checksum = "d52f4c29e2a68ac30c9087e1b772dc9f44a2b66ed44edf2266cf2be9b03dafc1"
 dependencies = [
  "cc",
  "pkg-config",
  "vcpkg",
 ]

-[[package]]
-name = "link-section"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2b1dd6fe32e55c0fc0ea9493aa57459ca3cf4ff3c857c7d0302290150da6e4f"
-
 [[package]]
 name = "linked-hash-map"
 version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"

-[[package]]
-name = "linktime-proc-macro"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c7b0a3383c2a1002d11349c92c85a666a5fb679e96c79d782cf0dbe557fd6ee"
-
 [[package]]
 name = "linux-raw-sys"
 version = "0.12.1"
@@ -2882,9 +3147,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"

 [[package]]
 name = "litemap"
-version = "0.8.2"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
+checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"

 [[package]]
 name = "litrs"
@@ -2903,9 +3168,9 @@ dependencies = [

 [[package]]
 name = "log"
-version = "0.4.32"
+version = "0.4.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"

 [[package]]
 name = "loole"
@@ -2917,6 +3182,15 @@ dependencies = [
  "futures-sink",
 ]

+[[package]]
+name = "loop9"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
+dependencies = [
+ "imgref",
+]
+
 [[package]]
 name = "lru-cache"
 version = "0.1.2"
@@ -2996,10 +3270,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"

 [[package]]
-name = "memchr"
-version = "2.8.2"
+name = "maybe-rayon"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
+checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
+dependencies = [
+ "cfg-if",
+ "rayon",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"

 [[package]]
 name = "memory-serve"
@@ -3017,6 +3301,16 @@ dependencies = [
  "walkdir",
 ]

+[[package]]
+name = "meowlnir-antispam"
+version = "0.1.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
+dependencies = [
+ "ruma-common",
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "mime"
 version = "0.3.17"
@@ -3035,15 +3329,15 @@ dependencies = [

 [[package]]
 name = "minicbor"
-version = "2.2.2"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b7a5041e12946f8b7d3f5a9d96383a19d694b9335457c522be7815b9abafb02"
+checksum = "e70eae6d4f18f7d76877fe7b13f0bc21f7c2b7239d2041c338335f7b388d0dd7"

 [[package]]
 name = "minicbor-serde"
-version = "0.7.0"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "293c7245401f035e2dcc4b12ebdb5c9d8847247fc79fe1b5b0a0d58d7275324c"
+checksum = "80047f75e28e3b38f6ab2ec3c2c7669f6b411fa6f8424e1a90a3fd784b19a3f4"
 dependencies = [
  "minicbor",
  "serde",
@@ -3076,9 +3370,9 @@ dependencies = [

 [[package]]
 name = "mio"
-version = "1.2.1"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
 dependencies = [
  "libc",
  "log",
@@ -3088,9 +3382,9 @@ dependencies = [

 [[package]]
 name = "moka"
-version = "0.12.15"
+version = "0.12.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046"
+checksum = "85f8024e1c8e71c778968af91d43700ce1d11b219d127d79fb2934153b82b42b"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-epoch",
@@ -3113,12 +3407,6 @@ dependencies = [
  "pxfm",
 ]

-[[package]]
-name = "ndk-context"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
-
 [[package]]
 name = "new_debug_unreachable"
 version = "1.0.6"
@@ -3127,9 +3415,21 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"

 [[package]]
 name = "nix"
-version = "0.31.3"
+version = "0.30.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
+checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
+name = "nix"
+version = "0.31.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -3162,12 +3462,24 @@ dependencies = [
  "memchr",
 ]

+[[package]]
+name = "nonempty"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7"
+
 [[package]]
 name = "nonzero_ext"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"

+[[package]]
+name = "noop_proc_macro"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
+
 [[package]]
 name = "nu-ansi-term"
 version = "0.50.3"
@@ -3212,9 +3524,20 @@ dependencies = [

 [[package]]
 name = "num-conv"
-version = "0.2.2"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
+checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]

 [[package]]
 name = "num-integer"
@@ -3434,6 +3757,15 @@ dependencies = [
  "memchr",
 ]

+[[package]]
+name = "oid-registry"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7"
+dependencies = [
+ "asn1-rs",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.21.4"
@@ -3452,36 +3784,36 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"

 [[package]]
 name = "opentelemetry"
-version = "0.32.0"
+version = "0.31.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0142c63252a9e054e68a4c61a5778f7b14f576274d593f8ce883d191a099682"
+checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0"
 dependencies = [
  "futures-core",
  "futures-sink",
  "js-sys",
  "pin-project-lite",
- "thiserror",
+ "thiserror 2.0.18",
  "tracing",
 ]

 [[package]]
 name = "opentelemetry-http"
-version = "0.32.0"
+version = "0.31.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5683015d09e2df236ef005b17f6f196f0d5f6313c4fa43a7b6a53b52776e4331"
+checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d"
 dependencies = [
  "async-trait",
  "bytes",
  "http",
  "opentelemetry",
- "reqwest 0.13.4",
+ "reqwest 0.12.28",
 ]

 [[package]]
 name = "opentelemetry-otlp"
-version = "0.32.0"
+version = "0.31.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9966929966d17620d7c316c643ba62631826e10021409357772d5eea84f62c35"
+checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf"
 dependencies = [
  "http",
  "opentelemetry",
@@ -3489,18 +3821,18 @@ dependencies = [
  "opentelemetry-proto",
  "opentelemetry_sdk",
  "prost",
- "reqwest 0.13.4",
- "thiserror",
+ "reqwest 0.12.28",
+ "thiserror 2.0.18",
  "tokio",
  "tonic",
- "tonic-types",
+ "tracing",
 ]

 [[package]]
 name = "opentelemetry-proto"
-version = "0.32.0"
+version = "0.31.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56d658ba1faf63f7b9c492cfbe6e0ec365440a16132d3270c1065f7b33f1b638"
+checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f"
 dependencies = [
  "opentelemetry",
  "opentelemetry_sdk",
@@ -3511,31 +3843,30 @@ dependencies = [

 [[package]]
 name = "opentelemetry_sdk"
-version = "0.32.1"
+version = "0.31.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b59f80e1ac4d5ff7a2db8fb6c80badb7f0f3f858211fba08dd9aaec750894f9"
+checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd"
 dependencies = [
  "futures-channel",
  "futures-executor",
  "futures-util",
  "opentelemetry",
  "percent-encoding",
- "portable-atomic",
- "rand 0.9.4",
- "thiserror",
+ "rand 0.9.2",
+ "thiserror 2.0.18",
  "tokio",
  "tokio-stream",
 ]

 [[package]]
 name = "os_info"
-version = "3.15.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf20a545b305cf1da722b236b5155c9bb35f1d5ceb28c048bd96ca842f41b5b"
+checksum = "e4022a17595a00d6a369236fdae483f0de7f0a339960a53118b818238e132224"
 dependencies = [
  "android_system_properties",
  "log",
- "nix",
+ "nix 0.30.1",
  "objc2",
  "objc2-foundation",
  "objc2-ui-kit",
@@ -3591,6 +3922,12 @@ version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"

+[[package]]
+name = "pastey"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
+
 [[package]]
 name = "pear"
 version = "0.2.9"
@@ -3656,7 +3993,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
 dependencies = [
  "phf_shared",
- "rand 0.8.6",
+ "rand 0.8.5",
 ]

 [[package]]
@@ -3670,18 +4007,18 @@ dependencies = [

 [[package]]
 name = "pin-project"
-version = "1.1.13"
+version = "1.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924"
+checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517"
 dependencies = [
  "pin-project-internal",
 ]

 [[package]]
 name = "pin-project-internal"
-version = "1.1.13"
+version = "1.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
+checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3694,6 +4031,12 @@ version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"

+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
 [[package]]
 name = "pkcs8"
 version = "0.10.2"
@@ -3706,9 +4049,9 @@ dependencies = [

 [[package]]
 name = "pkg-config"
-version = "0.3.33"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"

 [[package]]
 name = "png"
@@ -3731,9 +4074,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"

 [[package]]
 name = "potential_utf"
-version = "0.1.5"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
+checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
 dependencies = [
  "zerovec",
 ]
@@ -3759,17 +4102,6 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"

-[[package]]
-name = "prefix-trie"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7"
-dependencies = [
- "either",
- "ipnet",
- "num-traits",
-]
-
 [[package]]
 name = "prettyplease"
 version = "0.2.37"
@@ -3786,7 +4118,7 @@ version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
 dependencies = [
- "toml_edit 0.25.12+spec-1.1.0",
+ "toml_edit 0.25.5+spec-1.1.0",
 ]

 [[package]]
@@ -3834,10 +4166,29 @@ dependencies = [
 ]

 [[package]]
-name = "prost"
-version = "0.14.4"
+name = "profiling"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1"
+checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
+dependencies = [
+ "profiling-procmacros",
+]
+
+[[package]]
+name = "profiling-procmacros"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "prost"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568"
 dependencies = [
  "bytes",
  "prost-derive",
@@ -3845,9 +4196,9 @@ dependencies = [

 [[package]]
 name = "prost-derive"
-version = "0.14.4"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf"
+checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
 dependencies = [
  "anyhow",
  "itertools 0.14.0",
@@ -3858,18 +4209,28 @@ dependencies = [

 [[package]]
 name = "prost-types"
-version = "0.14.4"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a"
+checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7"
 dependencies = [
  "prost",
 ]

 [[package]]
-name = "pulldown-cmark"
-version = "0.13.4"
+name = "psm"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e"
+checksum = "3852766467df634d74f0b2d7819bf8dc483a0eb2e3b0f50f756f9cfe8b0d18d8"
+dependencies = [
+ "ar_archive_writer",
+ "cc",
+]
+
+[[package]]
+name = "pulldown-cmark"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83c41efbf8f90ac44de7f3a868f0867851d261b56291732d0cbf7cceaaeb55a6"
 dependencies = [
  "bitflags",
  "memchr",
@@ -3885,9 +4246,18 @@ checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"

 [[package]]
 name = "pxfm"
-version = "0.1.29"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f"
+checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d"
+
+[[package]]
+name = "qoi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
+dependencies = [
+ "bytemuck",
+]

 [[package]]
 name = "quick-error"
@@ -3909,8 +4279,8 @@ dependencies = [
  "quinn-udp",
  "rustc-hash",
  "rustls",
- "socket2",
- "thiserror",
+ "socket2 0.6.3",
+ "thiserror 2.0.18",
  "tokio",
  "tracing",
  "web-time",
@@ -3926,13 +4296,13 @@ dependencies = [
  "bytes",
  "getrandom 0.3.4",
  "lru-slab",
- "rand 0.9.4",
+ "rand 0.9.2",
  "ring",
  "rustc-hash",
  "rustls",
  "rustls-pki-types",
  "slab",
- "thiserror",
+ "thiserror 2.0.18",
  "tinyvec",
  "tracing",
  "web-time",
@@ -3947,25 +4317,25 @@ dependencies = [
  "cfg_aliases",
  "libc",
  "once_cell",
- "socket2",
+ "socket2 0.6.3",
  "tracing",
  "windows-sys 0.60.2",
 ]

 [[package]]
 name = "quote"
-version = "1.0.46"
+version = "1.0.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
 dependencies = [
  "proc-macro2",
 ]

 [[package]]
 name = "quoted_printable"
-version = "0.5.2"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478e0585659a122aa407eb7e3c0e1fa51b1d8a870038bd29f0cf4a8551eea972"
+checksum = "640c9bd8497b02465aeef5375144c26062e0dcd5939dfcbb0f5db76cb8c17c73"

 [[package]]
 name = "r-efi"
@@ -3981,18 +4351,18 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"

 [[package]]
 name = "rand"
-version = "0.8.6"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "rand_core 0.6.4",
 ]

 [[package]]
 name = "rand"
-version = "0.9.4"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
 dependencies = [
  "rand_chacha",
  "rand_core 0.9.5",
@@ -4000,13 +4370,13 @@ dependencies = [

 [[package]]
 name = "rand"
-version = "0.10.1"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
+checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8"
 dependencies = [
  "chacha20",
  "getrandom 0.4.2",
- "rand_core 0.10.1",
+ "rand_core 0.10.0",
 ]

 [[package]]
@@ -4039,9 +4409,79 @@ dependencies = [

 [[package]]
 name = "rand_core"
-version = "0.10.1"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
+
+[[package]]
+name = "rav1e"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
+dependencies = [
+ "aligned-vec",
+ "arbitrary",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "av-scenechange",
+ "av1-grain",
+ "bitstream-io",
+ "built",
+ "cfg-if",
+ "interpolate_name",
+ "itertools 0.14.0",
+ "libc",
+ "libfuzzer-sys",
+ "log",
+ "maybe-rayon",
+ "new_debug_unreachable",
+ "noop_proc_macro",
+ "num-derive",
+ "num-traits",
+ "paste",
+ "profiling",
+ "rand 0.9.2",
+ "rand_chacha",
+ "simd_helpers",
+ "thiserror 2.0.18",
+ "v_frame",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "ravif"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45"
+dependencies = [
+ "avif-serialize",
+ "imgref",
+ "loop9",
+ "quick-error",
+ "rav1e",
+ "rayon",
+ "rgb",
+]
+
+[[package]]
+name = "rayon"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]

 [[package]]
 name = "recaptcha-verify"
@@ -4065,9 +4505,9 @@ dependencies = [

 [[package]]
 name = "regex"
-version = "1.12.4"
+version = "1.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
+checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -4088,52 +4528,15 @@ dependencies = [

 [[package]]
 name = "regex-syntax"
-version = "0.8.11"
+version = "0.8.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"

 [[package]]
 name = "reqwest"
 version = "0.12.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
-dependencies = [
- "base64 0.22.1",
- "bytes",
- "futures-core",
- "http",
- "http-body",
- "http-body-util",
- "hyper",
- "hyper-rustls",
- "hyper-util",
- "js-sys",
- "log",
- "percent-encoding",
- "pin-project-lite",
- "rustls",
- "rustls-native-certs",
- "rustls-pki-types",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "sync_wrapper",
- "tokio",
- "tokio-rustls",
- "tower",
- "tower-http 0.6.11",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
-]
-
-[[package]]
-name = "reqwest"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
 dependencies = [
  "base64 0.22.1",
  "bytes",
@@ -4157,6 +4560,47 @@ dependencies = [
  "pin-project-lite",
  "quinn",
  "rustls",
+ "rustls-native-certs",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tokio-rustls",
+ "tokio-util",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+ "webpki-roots",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
  "rustls-pki-types",
  "rustls-platform-verifier",
  "serde",
@@ -4164,14 +4608,12 @@ dependencies = [
  "sync_wrapper",
  "tokio",
  "tokio-rustls",
- "tokio-util",
  "tower",
- "tower-http 0.6.11",
+ "tower-http",
  "tower-service",
  "url",
  "wasm-bindgen",
  "wasm-bindgen-futures",
- "wasm-streams",
  "web-sys",
 ]

@@ -4181,6 +4623,25 @@ version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"

+[[package]]
+name = "resolvematrix"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52dfcc6f56a81348db1fc6591356cfea9dc840408c75553b2fe225f86de43274"
+dependencies = [
+ "hickory-resolver",
+ "reqwest 0.13.2",
+ "serde",
+ "thiserror 2.0.18",
+ "tracing",
+]
+
+[[package]]
+name = "rgb"
+version = "0.8.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
+
 [[package]]
 name = "ring"
 version = "0.17.14"
@@ -4197,27 +4658,31 @@ dependencies = [

 [[package]]
 name = "ruma"
-version = "0.15.1"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.10.1"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "assign",
+ "continuwuity-admin-api",
+ "draupnir-antispam",
  "js_int",
  "js_option",
+ "meowlnir-antispam",
  "ruma-appservice-api",
  "ruma-client-api",
  "ruma-common",
  "ruma-events",
  "ruma-federation-api",
+ "ruma-identifiers-validation",
+ "ruma-identity-service-api",
  "ruma-push-gateway-api",
  "ruma-signatures",
- "ruma-state-res",
  "web-time",
 ]

 [[package]]
 name = "ruma-appservice-api"
-version = "0.15.0"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.10.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "js_int",
  "ruma-common",
@@ -4228,12 +4693,13 @@ dependencies = [

 [[package]]
 name = "ruma-client-api"
-version = "0.23.1"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.18.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "as_variant",
  "assign",
  "bytes",
+ "date_header",
  "http",
  "js_int",
  "js_option",
@@ -4243,69 +4709,72 @@ dependencies = [
  "serde",
  "serde_html_form",
  "serde_json",
- "thiserror",
+ "thiserror 2.0.18",
  "url",
  "web-time",
 ]

 [[package]]
 name = "ruma-common"
-version = "0.18.0"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.13.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "as_variant",
  "base64 0.22.1",
  "bytes",
- "date_header",
  "form_urlencoded",
- "getrandom 0.4.2",
+ "getrandom 0.2.17",
  "http",
  "indexmap",
  "js_int",
  "konst",
  "percent-encoding",
- "rand 0.10.1",
+ "rand 0.10.0",
  "regex",
  "ruma-identifiers-validation",
  "ruma-macros",
  "serde",
  "serde_html_form",
  "serde_json",
- "thiserror",
+ "smallvec",
+ "thiserror 2.0.18",
  "time",
  "tracing",
  "url",
  "uuid",
  "web-time",
  "wildmatch",
- "zeroize",
 ]

 [[package]]
 name = "ruma-events"
-version = "0.33.0"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.28.1"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "as_variant",
  "indexmap",
  "js_int",
  "js_option",
+ "percent-encoding",
  "pulldown-cmark",
+ "regex",
  "ruma-common",
+ "ruma-identifiers-validation",
  "ruma-macros",
  "serde",
  "serde_json",
- "thiserror",
+ "smallvec",
+ "thiserror 2.0.18",
  "tracing",
+ "url",
  "web-time",
  "wildmatch",
- "zeroize",
 ]

 [[package]]
 name = "ruma-federation-api"
-version = "0.14.0"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.9.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "bytes",
  "headers",
@@ -4315,31 +4784,39 @@ dependencies = [
  "js_int",
  "memchr",
  "mime",
- "rand 0.10.1",
+ "rand 0.10.0",
  "ruma-common",
  "ruma-events",
- "ruma-signatures",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 2.0.18",
  "tracing",
 ]

 [[package]]
 name = "ruma-identifiers-validation"
-version = "0.12.1"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.9.5"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "js_int",
- "thiserror",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "ruma-identity-service-api"
+version = "0.9.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
+dependencies = [
+ "js_int",
+ "ruma-common",
+ "serde",
 ]

 [[package]]
 name = "ruma-macros"
-version = "0.18.0"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.13.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
- "as_variant",
  "cfg-if",
  "proc-macro-crate",
  "proc-macro2",
@@ -4347,13 +4824,13 @@ dependencies = [
  "ruma-identifiers-validation",
  "serde",
  "syn",
- "toml 1.1.2+spec-1.1.0",
+ "toml 0.8.23",
 ]

 [[package]]
 name = "ruma-push-gateway-api"
-version = "0.14.0"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.9.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "js_int",
  "ruma-common",
@@ -4364,50 +4841,25 @@ dependencies = [

 [[package]]
 name = "ruma-signatures"
-version = "0.20.0"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
+version = "0.15.0"
+source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=1415caf8a32af4d943580c5ea4e12be1974593c2#1415caf8a32af4d943580c5ea4e12be1974593c2"
 dependencies = [
  "base64 0.22.1",
  "ed25519-dalek",
- "memchr",
  "pkcs8",
- "rand 0.10.1",
+ "rand 0.10.0",
+ "rand_core 0.6.4",
  "ruma-common",
  "serde_json",
- "sha2 0.10.9",
- "thiserror",
-]
-
-[[package]]
-name = "ruma-state-res"
-version = "0.16.0"
-source = "git+https://github.com/ruma/ruma.git?rev=3ecd80b92794d2d93f657a7b3db62d4be237526b#3ecd80b92794d2d93f657a7b3db62d4be237526b"
-dependencies = [
- "js_int",
- "ruma-common",
- "ruma-events",
- "ruma-signatures",
- "serde",
- "serde_json",
- "thiserror",
- "tracing",
-]
-
-[[package]]
-name = "ruminuwuity"
-version = "26.6.0-alpha.1"
-dependencies = [
- "assign",
- "ruma",
- "serde",
- "serde_json",
- "wildmatch",
+ "sha2",
+ "subslice",
+ "thiserror 2.0.18",
 ]

 [[package]]
 name = "rust-librocksdb-sys"
-version = "0.45.1+11.1.1"
-source = "git+https://forgejo.ellis.link/continuwuation/rust-rocksdb-zaidoon1?rev=0a25ff92f7c09b55eec496b9c192c7d5136ab2b8#0a25ff92f7c09b55eec496b9c192c7d5136ab2b8"
+version = "0.42.0+10.10.1"
+source = "git+https://forgejo.ellis.link/continuwuation/rust-rocksdb-zaidoon1?rev=31fb8f772c7afcdc0061ab6a40cfa3a1be2fccd9#31fb8f772c7afcdc0061ab6a40cfa3a1be2fccd9"
 dependencies = [
  "bindgen",
  "bzip2-sys",
@@ -4423,8 +4875,8 @@ dependencies = [

 [[package]]
 name = "rust-rocksdb"
-version = "0.49.1"
-source = "git+https://forgejo.ellis.link/continuwuation/rust-rocksdb-zaidoon1?rev=0a25ff92f7c09b55eec496b9c192c7d5136ab2b8#0a25ff92f7c09b55eec496b9c192c7d5136ab2b8"
+version = "0.46.0"
+source = "git+https://forgejo.ellis.link/continuwuation/rust-rocksdb-zaidoon1?rev=31fb8f772c7afcdc0061ab6a40cfa3a1be2fccd9#31fb8f772c7afcdc0061ab6a40cfa3a1be2fccd9"
 dependencies = [
  "libc",
  "parking_lot",
@@ -4439,9 +4891,9 @@ checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"

 [[package]]
 name = "rustc-hash"
-version = "2.1.2"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"

 [[package]]
 name = "rustc_version"
@@ -4452,6 +4904,15 @@ dependencies = [
  "semver",
 ]

+[[package]]
+name = "rusticata-macros"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
+dependencies = [
+ "nom 7.1.3",
+]
+
 [[package]]
 name = "rustix"
 version = "1.1.4"
@@ -4467,9 +4928,9 @@ dependencies = [

 [[package]]
 name = "rustls"
-version = "0.23.40"
+version = "0.23.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
+checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
 dependencies = [
  "aws-lc-rs",
  "log",
@@ -4483,9 +4944,9 @@ dependencies = [

 [[package]]
 name = "rustls-native-certs"
-version = "0.8.4"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
+checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
 dependencies = [
  "openssl-probe",
  "rustls-pki-types",
@@ -4494,10 +4955,19 @@ dependencies = [
 ]

 [[package]]
-name = "rustls-pki-types"
-version = "1.14.1"
+name = "rustls-pemfile"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
 dependencies = [
  "web-time",
  "zeroize",
@@ -4505,11 +4975,11 @@ dependencies = [

 [[package]]
 name = "rustls-platform-verifier"
-version = "0.7.0"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
+checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
 dependencies = [
- "core-foundation 0.10.1",
+ "core-foundation",
  "core-foundation-sys",
  "jni",
  "log",
@@ -4532,9 +5002,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"

 [[package]]
 name = "rustls-webpki"
-version = "0.103.13"
+version = "0.103.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
+checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
 dependencies = [
  "aws-lc-rs",
  "ring",
@@ -4558,7 +5028,7 @@ dependencies = [
  "futures-util",
  "pin-project",
  "thingbuf",
- "thiserror",
+ "thiserror 2.0.18",
  "unicode-segmentation",
 ]

@@ -4586,6 +5056,17 @@ dependencies = [
  "regex",
 ]

+[[package]]
+name = "saphyr-parser-bw"
+version = "0.0.608"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d55ae5ea09894b6d5382621db78f586df37ef18ab581bf32c754e75076b124b1"
+dependencies = [
+ "arraydeque",
+ "smallvec",
+ "thiserror 2.0.18",
+]
+
 [[package]]
 name = "schannel"
 version = "0.1.29"
@@ -4603,9 +5084,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"

 [[package]]
 name = "sd-notify"
-version = "0.5.0"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e4ef7359e694bfaf1dd27a30f9d760b54c00dfae9f19bd0c05a39bc9128fe76"
+checksum = "b943eadf71d8b69e661330cb0e2656e31040acf21ee7708e2c238a0ec6af2bf4"
 dependencies = [
  "libc",
 ]
@@ -4617,7 +5098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
 dependencies = [
  "bitflags",
- "core-foundation 0.10.1",
+ "core-foundation",
  "core-foundation-sys",
  "libc",
  "security-framework-sys",
@@ -4635,9 +5116,9 @@ dependencies = [

 [[package]]
 name = "semver"
-version = "1.0.28"
+version = "1.0.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
 dependencies = [
  "serde",
  "serde_core",
@@ -4645,13 +5126,14 @@ dependencies = [

 [[package]]
 name = "sentry"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "931a20b0da02350676e3d6d3c9028d58eaa448cf42a866712eec5845a505421e"
+checksum = "d92d893ba7469d361a6958522fa440e4e2bc8bf4c5803cd1bf40b9af63f8f9a8"
 dependencies = [
  "cfg_aliases",
  "httpdate",
- "reqwest 0.13.4",
+ "reqwest 0.12.28",
+ "rustls",
  "sentry-backtrace",
  "sentry-contexts",
  "sentry-core",
@@ -4661,13 +5143,14 @@ dependencies = [
  "sentry-tower",
  "sentry-tracing",
  "tokio",
+ "ureq",
 ]

 [[package]]
 name = "sentry-backtrace"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "911ee36abf5b7fa335fccd5f54361ba9c16baea5f0c3bb361a687b6c195c21cf"
+checksum = "5f8784d0a27b5cd4b5f75769ffc84f0b7580e3c35e1af9cd83cb90b612d769cc"
 dependencies = [
  "backtrace",
  "regex",
@@ -4676,9 +5159,9 @@ dependencies = [

 [[package]]
 name = "sentry-contexts"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b9d7d469e9e22741c17ca23fb8b42d79861590eb7cf330f3da34fc1e4bc1bc6"
+checksum = "0e5eb42f4cd4f9fdfec9e3b07b25a4c9769df83d218a7e846658984d5948ad3e"
 dependencies = [
  "hostname",
  "libc",
@@ -4690,11 +5173,11 @@ dependencies = [

 [[package]]
 name = "sentry-core"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "545dc562b6758d646ac19e1407f4ebc26d452111386743e03323464bc48bb2e0"
+checksum = "b0b1e7ca40f965db239da279bf278d87b7407469b98835f27f0c8e59ed189b06"
 dependencies = [
- "rand 0.9.4",
+ "rand 0.9.2",
  "sentry-types",
  "serde",
  "serde_json",
@@ -4703,9 +5186,9 @@ dependencies = [

 [[package]]
 name = "sentry-debug-images"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "660e9def38a573a869a182f7e90f58aaaa460f38b92b31fd1755ec537193bb48"
+checksum = "002561e49ea3a9de316e2efadc40fae553921b8ff41448f02ea85fd135a778d6"
 dependencies = [
  "findshlibs",
  "sentry-core",
@@ -4713,9 +5196,9 @@ dependencies = [

 [[package]]
 name = "sentry-log"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c13b9313bdd6a9db19e65ac0e4754e64dea6f18cdd15444656abb050db4538d"
+checksum = "e200860daf76e09f9ad111bce25928f96bedbb84bc5934b37f05bb445727c70e"
 dependencies = [
  "bitflags",
  "log",
@@ -4724,9 +5207,9 @@ dependencies = [

 [[package]]
 name = "sentry-panic"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "772d9de150c8ca910c835353c85f434457348fdd21208f9b3da3574202b1dc5d"
+checksum = "8906f8be87aea5ac7ef937323fb655d66607427f61007b99b7cb3504dc5a156c"
 dependencies = [
  "sentry-backtrace",
  "sentry-core",
@@ -4734,9 +5217,9 @@ dependencies = [

 [[package]]
 name = "sentry-tower"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2abea154597936d5df2d39fbe8aac16d584de6b3572c70c39558764d9d2efe15"
+checksum = "56aebe376310840b49dad4cca55c7b32d9abdc14946cd071d4158ecb149b63a4"
 dependencies = [
  "http",
  "pin-project",
@@ -4748,9 +5231,9 @@ dependencies = [

 [[package]]
 name = "sentry-tracing"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c51ec9620a4d398dcdf7ee90effbf8d8691cfa24e91978bfa8565cac039d4980"
+checksum = "5b07eefe04486316c57aba08ab53dd44753c25102d1d3fe05775cc93a13262d9"
 dependencies = [
  "bitflags",
  "sentry-backtrace",
@@ -4761,16 +5244,16 @@ dependencies = [

 [[package]]
 name = "sentry-types"
-version = "0.48.2"
+version = "0.46.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "041359745a44dd2e14fe21b7510fe7ca8b5beffce6636a0b52e5bc7d5f736887"
+checksum = "567711f01f86a842057e1fc17779eba33a336004227e1a1e7e6cc2599e22e259"
 dependencies = [
  "debugid",
  "hex",
- "rand 0.9.4",
+ "rand 0.9.2",
  "serde",
  "serde_json",
- "thiserror",
+ "thiserror 2.0.18",
  "time",
  "url",
  "uuid",
@@ -4788,18 +5271,19 @@ dependencies = [

 [[package]]
 name = "serde-saphyr"
-version = "0.0.27"
+version = "0.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5897b4c3faadadd35fdb6689f015641f3bc481d5adaaac56231ea15aeb243db3"
+checksum = "4a6fc4aa0da972ba0f51cf5c1bb16e9dba35334adc6831b09b3ffb0ec20bb264"
 dependencies = [
  "ahash",
  "annotate-snippets",
  "base64 0.22.1",
  "encoding_rs_io",
  "getrandom 0.3.4",
- "granit-parser",
  "nohash-hasher",
  "num-traits",
+ "regex",
+ "saphyr-parser-bw",
  "serde",
  "smallvec",
  "zmij",
@@ -4827,9 +5311,9 @@ dependencies = [

 [[package]]
 name = "serde_html_form"
-version = "0.4.0"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0946d52b4b7e28823148aebbeceb901012c595ad737920d504fa8634bb099e6f"
+checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f"
 dependencies = [
  "form_urlencoded",
  "indexmap",
@@ -4840,9 +5324,9 @@ dependencies = [

 [[package]]
 name = "serde_json"
-version = "1.0.150"
+version = "1.0.149"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
 dependencies = [
  "itoa",
  "memchr",
@@ -4864,9 +5348,9 @@ dependencies = [

 [[package]]
 name = "serde_regex"
-version = "1.2.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bafc8d0c5330cecff10f16b459b479fd9acaa5b4acd7167301414e21b0057012"
+checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf"
 dependencies = [
  "regex",
  "serde",
@@ -4883,9 +5367,9 @@ dependencies = [

 [[package]]
 name = "serde_spanned"
-version = "1.1.1"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
+checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
 dependencies = [
  "serde_core",
 ]
@@ -4910,18 +5394,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
 dependencies = [
  "cfg-if",
  "cpufeatures 0.2.17",
- "digest 0.10.7",
-]
-
-[[package]]
-name = "sha1"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214"
-dependencies = [
- "cfg-if",
- "cpufeatures 0.3.0",
- "digest 0.11.3",
+ "digest",
 ]

 [[package]]
@@ -4932,18 +5405,7 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
 dependencies = [
  "cfg-if",
  "cpufeatures 0.2.17",
- "digest 0.10.7",
-]
-
-[[package]]
-name = "sha2"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
-dependencies = [
- "cfg-if",
- "cpufeatures 0.3.0",
- "digest 0.11.3",
+ "digest",
 ]

 [[package]]
@@ -4955,7 +5417,7 @@ dependencies = [
  "async-trait",
  "bytes",
  "hex",
- "sha2 0.10.9",
+ "sha2",
  "tokio",
 ]

@@ -4974,12 +5436,6 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"

-[[package]]
-name = "shlex"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
-
 [[package]]
 name = "signal-hook"
 version = "0.3.18"
@@ -5022,31 +5478,24 @@ dependencies = [

 [[package]]
 name = "simd-adler32"
-version = "0.3.9"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
+checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"

 [[package]]
-name = "simd_cesu8"
-version = "1.1.1"
+name = "simd_helpers"
+version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33"
+checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
 dependencies = [
- "rustc_version",
- "simdutf8",
+ "quote",
 ]

-[[package]]
-name = "simdutf8"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
-
 [[package]]
 name = "siphasher"
-version = "1.0.3"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
+checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"

 [[package]]
 name = "slab"
@@ -5066,18 +5515,28 @@ dependencies = [

 [[package]]
 name = "smallvec"
-version = "1.15.2"
+version = "1.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
 dependencies = [
  "serde",
 ]

 [[package]]
 name = "socket2"
-version = "0.6.4"
+version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "socket2"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
 dependencies = [
  "libc",
  "windows-sys 0.61.2",
@@ -5108,6 +5567,19 @@ version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"

+[[package]]
+name = "stacker"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d74a23609d509411d10e2176dc2a4346e3b4aea2e7b1869f19fdedbc71c013"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "libc",
+ "psm",
+ "windows-sys 0.59.0",
+]
+
 [[package]]
 name = "strict"
 version = "0.2.0"
@@ -5145,6 +5617,15 @@ version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"

+[[package]]
+name = "subslice"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a8e4809a3bb02de01f1f7faf1ba01a83af9e8eabcd4d31dd6e413d14d56aae"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "subtle"
 version = "2.6.1"
@@ -5153,9 +5634,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"

 [[package]]
 name = "syn"
-version = "2.0.118"
+version = "2.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5182,27 +5663,6 @@ dependencies = [
  "syn",
 ]

-[[package]]
-name = "system-configuration"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
-dependencies = [
- "bitflags",
- "core-foundation 0.9.4",
- "system-configuration-sys",
-]
-
-[[package]]
-name = "system-configuration-sys"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
 [[package]]
 name = "tagptr"
 version = "0.2.0"
@@ -5232,7 +5692,7 @@ dependencies = [
  "lazy-regex",
  "minimad",
  "serde",
- "thiserror",
+ "thiserror 2.0.18",
  "unicode-width 0.1.14",
 ]

@@ -5246,13 +5706,33 @@ dependencies = [
  "pin-project",
 ]

+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
 [[package]]
 name = "thiserror"
 version = "2.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
 dependencies = [
- "thiserror-impl",
+ "thiserror-impl 2.0.18",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]

 [[package]]
@@ -5275,6 +5755,20 @@ dependencies = [
  "cfg-if",
 ]

+[[package]]
+name = "tiff"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
+dependencies = [
+ "fax",
+ "flate2",
+ "half",
+ "quick-error",
+ "weezl",
+ "zune-jpeg",
+]
+
 [[package]]
 name = "tikv-jemalloc-ctl"
 version = "0.6.1"
@@ -5305,11 +5799,12 @@ dependencies = [

 [[package]]
 name = "time"
-version = "0.3.49"
+version = "0.3.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
 dependencies = [
  "deranged",
+ "itoa",
  "num-conv",
  "powerfmt",
  "serde_core",
@@ -5319,15 +5814,15 @@ dependencies = [

 [[package]]
 name = "time-core"
-version = "0.1.9"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"

 [[package]]
 name = "time-macros"
-version = "0.2.29"
+version = "0.2.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d"
+checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
 dependencies = [
  "num-conv",
  "time-core",
@@ -5335,9 +5830,9 @@ dependencies = [

 [[package]]
 name = "tinystr"
-version = "0.8.3"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
+checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
 dependencies = [
  "displaydoc",
  "zerovec",
@@ -5360,16 +5855,16 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"

 [[package]]
 name = "tokio"
-version = "1.52.3"
+version = "1.50.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
+checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
 dependencies = [
  "bytes",
  "libc",
  "mio",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2",
+ "socket2 0.6.3",
  "tokio-macros",
  "tracing",
  "windows-sys 0.61.2",
@@ -5377,9 +5872,9 @@ dependencies = [

 [[package]]
 name = "tokio-macros"
-version = "2.7.0"
+version = "2.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
+checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5388,9 +5883,9 @@ dependencies = [

 [[package]]
 name = "tokio-metrics"
-version = "0.5.0"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9e81d53caf955549b1dec7af4ac2149e94cc25ed97b4a545151140281e2f528"
+checksum = "0e0410015c6db7b67b9c9ab2a3af4d74a942d637ff248d0d055073750deac6f9"
 dependencies = [
  "futures-util",
  "pin-project-lite",
@@ -5452,26 +5947,13 @@ checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
 dependencies = [
  "indexmap",
  "serde_core",
- "serde_spanned 1.1.1",
+ "serde_spanned 1.0.4",
  "toml_datetime 0.7.5+spec-1.1.0",
  "toml_parser",
  "toml_writer",
  "winnow 0.7.15",
 ]

-[[package]]
-name = "toml"
-version = "1.1.2+spec-1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
-dependencies = [
- "serde_core",
- "serde_spanned 1.1.1",
- "toml_datetime 1.1.1+spec-1.1.0",
- "toml_parser",
- "winnow 1.0.3",
-]
-
 [[package]]
 name = "toml_datetime"
 version = "0.6.11"
@@ -5492,9 +5974,9 @@ dependencies = [

 [[package]]
 name = "toml_datetime"
-version = "1.1.1+spec-1.1.0"
+version = "1.0.1+spec-1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
+checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9"
 dependencies = [
  "serde_core",
 ]
@@ -5515,23 +5997,23 @@ dependencies = [

 [[package]]
 name = "toml_edit"
-version = "0.25.12+spec-1.1.0"
+version = "0.25.5+spec-1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
+checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1"
 dependencies = [
  "indexmap",
- "toml_datetime 1.1.1+spec-1.1.0",
+ "toml_datetime 1.0.1+spec-1.1.0",
  "toml_parser",
- "winnow 1.0.3",
+ "winnow 1.0.0",
 ]

 [[package]]
 name = "toml_parser"
-version = "1.1.2+spec-1.1.0"
+version = "1.0.10+spec-1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
+checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420"
 dependencies = [
- "winnow 1.0.3",
+ "winnow 1.0.0",
 ]

 [[package]]
@@ -5542,15 +6024,15 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"

 [[package]]
 name = "toml_writer"
-version = "1.1.1+spec-1.1.0"
+version = "1.0.7+spec-1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
+checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d"

 [[package]]
 name = "tonic"
-version = "0.14.6"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef"
+checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec"
 dependencies = [
  "async-trait",
  "axum",
@@ -5565,7 +6047,7 @@ dependencies = [
  "hyper-util",
  "percent-encoding",
  "pin-project",
- "socket2",
+ "socket2 0.6.3",
  "sync_wrapper",
  "tokio",
  "tokio-stream",
@@ -5577,26 +6059,15 @@ dependencies = [

 [[package]]
 name = "tonic-prost"
-version = "0.14.6"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0"
+checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309"
 dependencies = [
  "bytes",
  "prost",
  "tonic",
 ]

-[[package]]
-name = "tonic-types"
-version = "0.14.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73ab1b02061f83d519bba3caa167f88f261ef05720ab8ebc954ade70de3348e8"
-dependencies = [
- "prost",
- "prost-types",
- "tonic",
-]
-
 [[package]]
 name = "tower"
 version = "0.5.3"
@@ -5618,9 +6089,9 @@ dependencies = [

 [[package]]
 name = "tower-http"
-version = "0.6.11"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
+checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
 dependencies = [
  "async-compression",
  "bitflags",
@@ -5630,30 +6101,7 @@ dependencies = [
  "http",
  "http-body",
  "http-body-util",
- "pin-project-lite",
- "tokio",
- "tokio-util",
- "tower",
- "tower-layer",
- "tower-service",
- "url",
-]
-
-[[package]]
-name = "tower-http"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233"
-dependencies = [
- "async-compression",
- "bitflags",
- "bytes",
- "futures-core",
- "futures-util",
- "http",
- "http-body",
- "http-body-util",
- "percent-encoding",
+ "iri-string",
  "pin-project-lite",
  "tokio",
  "tokio-util",
@@ -5755,9 +6203,9 @@ dependencies = [

 [[package]]
 name = "tracing-opentelemetry"
-version = "0.33.0"
+version = "0.32.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adbc64cba7137545b8044cb1fe9814f7aacf3c6b5f9b45be8bb5db538befdb26"
+checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc"
 dependencies = [
  "js-sys",
  "opentelemetry",
@@ -5795,15 +6243,24 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"

 [[package]]
 name = "typenum"
-version = "1.20.1"
+version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"

 [[package]]
 name = "typewit"
-version = "1.15.2"
+version = "1.14.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "214ca0b2191785cbc06209b9ca1861e048e39b5ba33574b3cedd58363d5bb5f6"
+checksum = "f8c1ae7cc0fdb8b842d65d127cb981574b0d2b249b74d1c7a2986863dc134f71"
+dependencies = [
+ "typewit_proc_macros",
+]
+
+[[package]]
+name = "typewit_proc_macros"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e36a83ea2b3c704935a01b4642946aadd445cea40b10935e3f8bd8052b8193d6"

 [[package]]
 name = "uname"
@@ -5837,9 +6294,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"

 [[package]]
 name = "unicode-segmentation"
-version = "1.13.3"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"

 [[package]]
 name = "unicode-width"
@@ -5865,6 +6322,34 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"

+[[package]]
+name = "ureq"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc97a28575b85cfedf2a7e7d3cc64b3e11bd8ac766666318003abbacc7a21fc"
+dependencies = [
+ "base64 0.22.1",
+ "log",
+ "percent-encoding",
+ "rustls",
+ "rustls-pki-types",
+ "ureq-proto",
+ "utf-8",
+ "webpki-roots",
+]
+
+[[package]]
+name = "ureq-proto"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f"
+dependencies = [
+ "base64 0.22.1",
+ "http",
+ "httparse",
+ "log",
+]
+
 [[package]]
 name = "url"
 version = "2.5.8"
@@ -5898,9 +6383,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"

 [[package]]
 name = "uuid"
-version = "1.23.3"
+version = "1.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7"
+checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37"
 dependencies = [
  "getrandom 0.4.2",
  "js-sys",
@@ -5908,6 +6393,17 @@ dependencies = [
  "wasm-bindgen",
 ]

+[[package]]
+name = "v_frame"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
+dependencies = [
+ "aligned-vec",
+ "num-traits",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "validator"
 version = "0.20.0"
@@ -5983,11 +6479,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"

 [[package]]
 name = "wasip2"
-version = "1.0.4+wasi-0.2.12"
+version = "1.0.2+wasi-0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
 dependencies = [
- "wit-bindgen 0.57.1",
+ "wit-bindgen",
 ]

 [[package]]
@@ -5996,14 +6492,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
 dependencies = [
- "wit-bindgen 0.51.0",
+ "wit-bindgen",
 ]

 [[package]]
 name = "wasm-bindgen"
-version = "0.2.125"
+version = "0.2.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
+checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -6014,19 +6510,23 @@ dependencies = [

 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.75"
+version = "0.4.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280"
+checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
 dependencies = [
+ "cfg-if",
+ "futures-util",
  "js-sys",
+ "once_cell",
  "wasm-bindgen",
+ "web-sys",
 ]

 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.125"
+version = "0.2.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
+checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -6034,9 +6534,9 @@ dependencies = [

 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.125"
+version = "0.2.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
+checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
 dependencies = [
  "bumpalo",
  "proc-macro2",
@@ -6047,9 +6547,9 @@ dependencies = [

 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.125"
+version = "0.2.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
+checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
 dependencies = [
  "unicode-ident",
 ]
@@ -6078,9 +6578,9 @@ dependencies = [

 [[package]]
 name = "wasm-streams"
-version = "0.5.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb"
+checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
 dependencies = [
  "futures-util",
  "js-sys",
@@ -6103,9 +6603,9 @@ dependencies = [

 [[package]]
 name = "web-sys"
-version = "0.3.102"
+version = "0.3.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d"
+checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -6135,9 +6635,18 @@ dependencies = [

 [[package]]
 name = "webpki-root-certs"
-version = "1.0.7"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c"
+checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
 dependencies = [
  "rustls-pki-types",
 ]
@@ -6198,32 +6707,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"

 [[package]]
-name = "windows-registry"
-version = "0.6.1"
+name = "windows-sys"
+version = "0.45.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
 dependencies = [
- "windows-link",
- "windows-result",
- "windows-strings",
+ "windows-targets 0.42.2",
 ]

 [[package]]
-name = "windows-result"
-version = "0.4.1"
+name = "windows-sys"
+version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-link",
-]
-
-[[package]]
-name = "windows-strings"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
-dependencies = [
- "windows-link",
+ "windows-targets 0.48.5",
 ]

 [[package]]
@@ -6235,6 +6733,15 @@ dependencies = [
  "windows-targets 0.52.6",
 ]

+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.60.2"
@@ -6253,6 +6760,36 @@ dependencies = [
  "windows-link",
 ]

+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
 [[package]]
 name = "windows-targets"
 version = "0.52.6"
@@ -6286,6 +6823,18 @@ dependencies = [
  "windows_x86_64_msvc 0.53.1",
 ]

+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
 [[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.52.6"
@@ -6298,6 +6847,18 @@ version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"

+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.52.6"
@@ -6310,6 +6871,18 @@ version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"

+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
 [[package]]
 name = "windows_i686_gnu"
 version = "0.52.6"
@@ -6334,6 +6907,18 @@ version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"

+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
 [[package]]
 name = "windows_i686_msvc"
 version = "0.52.6"
@@ -6346,6 +6931,18 @@ version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"

+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.52.6"
@@ -6358,6 +6955,18 @@ version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"

+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.52.6"
@@ -6370,6 +6979,18 @@ version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"

+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.52.6"
@@ -6393,13 +7014,23 @@ dependencies = [

 [[package]]
 name = "winnow"
-version = "1.0.3"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
+checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
 dependencies = [
  "memchr",
 ]

+[[package]]
+name = "winreg"
+version = "0.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "wit-bindgen"
 version = "0.51.0"
@@ -6409,12 +7040,6 @@ dependencies = [
  "wit-bindgen-rust-macro",
 ]

-[[package]]
-name = "wit-bindgen"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
-
 [[package]]
 name = "wit-bindgen-core"
 version = "0.51.0"
@@ -6496,9 +7121,26 @@ dependencies = [

 [[package]]
 name = "writeable"
-version = "0.6.3"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
+checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
+
+[[package]]
+name = "x509-parser"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202"
+dependencies = [
+ "asn1-rs",
+ "data-encoding",
+ "der-parser",
+ "lazy_static",
+ "nom 7.1.3",
+ "oid-registry",
+ "rusticata-macros",
+ "thiserror 2.0.18",
+ "time",
+]

 [[package]]
 name = "xml5ever"
@@ -6513,7 +7155,7 @@ dependencies = [

 [[package]]
 name = "xtask"
-version = "26.6.0-alpha.1"
+version = "0.5.7-alpha.1"
 dependencies = [
  "askama",
  "cargo_metadata",
@@ -6522,6 +7164,12 @@ dependencies = [
  "conduwuit_admin",
 ]

+[[package]]
+name = "y4m"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
+
 [[package]]
 name = "yansi"
 version = "1.0.1"
@@ -6530,9 +7178,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"

 [[package]]
 name = "yoke"
-version = "0.8.3"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
+checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
 dependencies = [
  "stable_deref_trait",
  "yoke-derive",
@@ -6541,9 +7189,9 @@ dependencies = [

 [[package]]
 name = "yoke-derive"
-version = "0.8.2"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -6553,18 +7201,18 @@ dependencies = [

 [[package]]
 name = "zerocopy"
-version = "0.8.52"
+version = "0.8.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
+checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3"
 dependencies = [
  "zerocopy-derive",
 ]

 [[package]]
 name = "zerocopy-derive"
-version = "0.8.52"
+version = "0.8.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
+checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -6573,18 +7221,18 @@ dependencies = [

 [[package]]
 name = "zerofrom"
-version = "0.1.8"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
 dependencies = [
  "zerofrom-derive",
 ]

 [[package]]
 name = "zerofrom-derive"
-version = "0.1.7"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -6594,15 +7242,15 @@ dependencies = [

 [[package]]
 name = "zeroize"
-version = "1.9.0"
+version = "1.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"

 [[package]]
 name = "zerotrie"
-version = "0.2.4"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
+checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
 dependencies = [
  "displaydoc",
  "yoke",
@@ -6611,9 +7259,9 @@ dependencies = [

 [[package]]
 name = "zerovec"
-version = "0.11.6"
+version = "0.11.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
+checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
 dependencies = [
  "yoke",
  "zerofrom",
@@ -6622,9 +7270,9 @@ dependencies = [

 [[package]]
 name = "zerovec-derive"
-version = "0.11.3"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
+checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -6672,10 +7320,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"

 [[package]]
-name = "zune-jpeg"
-version = "0.5.15"
+name = "zune-inflate"
+version = "0.2.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
+checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "zune-jpeg"
+version = "0.5.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c"
 dependencies = [
  "zune-core",
 ]
diff --git c/Cargo.toml i/Cargo.toml
index 519de9d2d..131aa6bf6 100644
--- c/Cargo.toml
+++ i/Cargo.toml
@@ -559,6 +559,9 @@ features = ["std"]
 [workspace.dependencies.nonzero_ext]
 version = "0.3.0"

+[workspace.dependencies.resolvematrix]
+version = "0.0.3"
+
 #
 # Patches
 #
diff --git c/src/admin/Cargo.toml i/src/admin/Cargo.toml
index 4afed12b4..1f82978a4 100644
--- c/src/admin/Cargo.toml
+++ i/src/admin/Cargo.toml
@@ -92,6 +92,7 @@ serde-saphyr.workspace = true
 tokio.workspace = true
 tracing-subscriber.workspace = true
 tracing.workspace = true
+resolvematrix.workspace = true

 [lints]
 workspace = true
diff --git c/src/admin/debug/commands.rs i/src/admin/debug/commands.rs
index 1aa9cb062..b6bf16ae0 100644
--- c/src/admin/debug/commands.rs
+++ i/src/admin/debug/commands.rs
@@ -20,6 +20,7 @@
 };
 use futures::{FutureExt, StreamExt, TryStreamExt};
 use lettre::message::Mailbox;
+use resolvematrix::server::{MatrixResolver, ResolvedDestination};
 use ruma::{
 	CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId,
 	OwnedRoomOrAliasId, OwnedServerName, RoomId, RoomVersionId, UInt,
@@ -1007,13 +1008,20 @@ pub(super) async fn resolve_true_destination(
 		);
 	}

-	let actual = self
-		.services
-		.resolver
-		.resolve_actual_dest(&server_name, !no_cache)
-		.await?;
+	let resolver: &MatrixResolver = if no_cache {
+		&MatrixResolver::new()?
+	} else {
+		&self.services.resolver.resolver
+	};

-	let msg = format!("Destination: {}\nHostname URI: {}", actual.dest, actual.host);
+	let actual = resolver.resolve_server(&server_name.as_str()).await?;
+
+	let destination = match actual.destination {
+		| ResolvedDestination::Literal(addr) => addr.to_string(),
+		| ResolvedDestination::Named(host, port) => format!("{host}:{port}"),
+	};
+
+	let msg = format!("Destination: {}\nHostname URI (SNI): {}", destination, actual.host);
 	self.write_str(&msg).await
 }

diff --git c/src/admin/query/resolver.rs i/src/admin/query/resolver.rs
index d651e5bff..e2cb5eca3 100644
--- c/src/admin/query/resolver.rs
+++ i/src/admin/query/resolver.rs
@@ -46,7 +46,7 @@ async fn destinations_cache(&self, server_name: Option<OwnedServerName>) -> Resu
 	writeln!(self, "| Server Name | Destination | Hostname | Expires |").await?;
 	writeln!(self, "| ----------- | ----------- | -------- | ------- |").await?;

-	let mut destinations = self.services.resolver.cache.destinations().boxed();
+	let mut destinations = self.services.resolver.dns.cache.destinations().boxed();

 	while let Some((name, CachedDest { dest, host, expire })) = destinations.next().await {
 		if let Some(server_name) = server_name.as_ref() {
@@ -70,7 +70,7 @@ async fn overrides_cache(&self, server_name: Option<String>) -> Result {
 	writeln!(self, "| Server Name | IP  | Port | Expires | Overriding |").await?;
 	writeln!(self, "| ----------- | --- | ----:| ------- | ---------- |").await?;

-	let mut overrides = self.services.resolver.cache.overrides().boxed();
+	let mut overrides = self.services.resolver.dns.cache.overrides().boxed();

 	while let Some((name, CachedOverride { ips, port, expire, overriding })) =
 		overrides.next().await
@@ -92,11 +92,11 @@ async fn overrides_cache(&self, server_name: Option<String>) -> Result {
 #[admin_command]
 async fn flush_cache(&self, name: Option<OwnedServerName>, all: bool) -> Result {
 	if all {
-		self.services.resolver.cache.clear().await;
+		self.services.resolver.dns.cache.clear().await;
 		writeln!(self, "Resolver caches cleared!").await
 	} else if let Some(name) = name {
-		self.services.resolver.cache.del_destination(&name);
-		self.services.resolver.cache.del_override(&name);
+		self.services.resolver.dns.cache.del_destination(&name);
+		self.services.resolver.dns.cache.del_override(&name);
 		self.write_str(&format!("Cleared {name} from resolver caches!"))
 			.await
 	} else {
diff --git c/src/core/Cargo.toml i/src/core/Cargo.toml
index 093b50f71..d99184b9d 100644
--- c/src/core/Cargo.toml
+++ i/src/core/Cargo.toml
@@ -117,6 +117,7 @@ url.workspace = true
 parking_lot.workspace = true
 lock_api.workspace = true
 hyper-util.workspace = true
+resolvematrix.workspace = true

 [target.'cfg(unix)'.dependencies]
 nix.workspace = true
diff --git c/src/core/error/mod.rs i/src/core/error/mod.rs
index 703726043..af7520c02 100644
--- c/src/core/error/mod.rs
+++ i/src/core/error/mod.rs
@@ -87,6 +87,8 @@ pub enum Error {
 	YamlDe(#[from] serde_saphyr::Error),
 	#[error(transparent)]
 	YamlSer(#[from] serde_saphyr::ser_error::Error),
+	#[error(transparent)]
+	ResolveServer(#[from] resolvematrix::server::ResolveServerError),

 	// ruma/conduwuit
 	#[error("Arithmetic operation failed: {0}")]
diff --git c/src/service/Cargo.toml i/src/service/Cargo.toml
index a0568db0b..0f63bd8ed 100644
--- c/src/service/Cargo.toml
+++ i/src/service/Cargo.toml
@@ -119,6 +119,7 @@ recaptcha-verify = { version = "0.2.0", default-features = false }
 reqwest_recaptcha = { package = "reqwest", version = "0.12.28", default-features = false, features = ["rustls-tls-native-roots-no-provider"]  } # As long as recaptcha-verify's reqwest is outdated
 yansi.workspace = true
 lettre.workspace = true
+resolvematrix.workspace = true

 [target.'cfg(all(unix, target_os = "linux"))'.dependencies]
 sd-notify.workspace = true
diff --git c/src/service/client/mod.rs i/src/service/client/mod.rs
index 4792bd7ad..b17aab9ab 100644
--- c/src/service/client/mod.rs
+++ i/src/service/client/mod.rs
@@ -43,7 +43,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {

 		Ok(Arc::new(Self {
 			default: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.build()?,

 			url_preview: base(config)
@@ -51,19 +51,19 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 					builder_interface(builder, url_preview_bind_iface.as_deref())
 				})?
 				.local_address(url_preview_bind_addr)
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.timeout(Duration::from_secs(config.url_preview_timeout))
 				.redirect(redirect::Policy::limited(3))
 				.user_agent(url_preview_user_agent)
 				.build()?,

 			extern_media: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.redirect(redirect::Policy::limited(3))
 				.build()?,

 			well_known: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.connect_timeout(Duration::from_secs(config.well_known_conn_timeout))
 				.read_timeout(Duration::from_secs(config.well_known_timeout))
 				.timeout(Duration::from_secs(config.well_known_timeout))
@@ -72,7 +72,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			federation: base(config)?
-				.dns_resolver(resolver.resolver.hooked.clone())
+				.dns_resolver(resolver.dns.resolver.hooked.clone())
 				.connect_timeout(Duration::from_secs(config.federation_conn_timeout))
 				.read_timeout(Duration::from_secs(config.federation_timeout))
 				.timeout(Duration::from_secs(
@@ -86,7 +86,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			synapse: base(config)?
-				.dns_resolver(resolver.resolver.hooked.clone())
+				.dns_resolver(resolver.dns.resolver.hooked.clone())
 				.connect_timeout(Duration::from_secs(config.federation_conn_timeout))
 				.read_timeout(Duration::from_secs(config.federation_timeout.saturating_mul(6)))
 				.timeout(Duration::from_secs(
@@ -100,7 +100,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			sender: base(config)?
-				.dns_resolver(resolver.resolver.hooked.clone())
+				.dns_resolver(resolver.dns.resolver.hooked.clone())
 				.connect_timeout(Duration::from_secs(config.federation_conn_timeout))
 				.read_timeout(Duration::from_secs(config.sender_timeout))
 				.timeout(Duration::from_secs(config.sender_timeout))
@@ -110,7 +110,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			appservice: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.connect_timeout(Duration::from_secs(5))
 				.read_timeout(Duration::from_secs(config.appservice_timeout))
 				.timeout(Duration::from_secs(config.appservice_timeout))
@@ -120,7 +120,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			pusher: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.connect_timeout(Duration::from_secs(config.pusher_conn_timeout))
 				.timeout(Duration::from_secs(config.pusher_timeout))
 				.pool_max_idle_per_host(1)
diff --git c/src/service/federation/execute.rs i/src/service/federation/execute.rs
index 0c147c1ef..4318bb016 100644
--- c/src/service/federation/execute.rs
+++ i/src/service/federation/execute.rs
@@ -7,6 +7,7 @@
 };
 use ipaddress::IPAddress;
 use reqwest::{Client, Method, Request, Response, Url};
+use resolvematrix::server::Resolution;
 use ruma::{
 	ServerName,
 	api::{
@@ -132,7 +133,7 @@ pub async fn execute_on<'i, T, PathBuilderInput>(
 async fn perform<T>(
 	&self,
 	dest: &ServerName,
-	actual: &ActualDest,
+	actual: &Resolution,
 	request: Request,
 	client: &Client,
 ) -> Result<T::IncomingResponse>
@@ -168,7 +169,7 @@ fn validate_url(&self, url: &Url) -> Result<()> {
 async fn handle_response<T>(
 	&self,
 	dest: &ServerName,
-	actual: &ActualDest,
+	actual: &Resolution,
 	method: &Method,
 	url: &Url,
 	response: Response,
@@ -199,7 +200,7 @@ async fn handle_response<T>(

 async fn into_http_response(
 	dest: &ServerName,
-	actual: &ActualDest,
+	actual: &Resolution,
 	method: &Method,
 	url: &Url,
 	mut response: Response,
@@ -211,7 +212,7 @@ async fn into_http_response(
 		request_url = %url,
 		response_url = %response.url(),
 		"Received response from {}",
-		actual.string(),
+		actual.base_url(),
 	);

 	let mut http_response_builder = http::Response::builder()
@@ -248,7 +249,7 @@ async fn into_http_response(
 }

 fn handle_error(
-	actual: &ActualDest,
+	actual: &Resolution,
 	method: &Method,
 	url: &Url,
 	mut e: reqwest::Error,
diff --git c/src/service/resolver/actual.rs i/src/service/resolver/actual.rs
index 1ca3b595c..e69de29bb 100644
--- c/src/service/resolver/actual.rs
+++ i/src/service/resolver/actual.rs
@@ -1,441 +0,0 @@
-use std::fmt::Debug;
-
-use conduwuit::{Err, Result, debug, debug_info, err, error, trace};
-use futures::{FutureExt, TryFutureExt};
-use hickory_resolver::{
-	net::{DnsError, NetError},
-	proto::rr::rdata::SRV,
-};
-use ipaddress::IPAddress;
-use ruma::ServerName;
-
-use super::{
-	cache::{CachedDest, CachedOverride, MAX_IPS},
-	fed::{FedDest, PortString, add_port_to_hostname, ensure_host_has_port, get_ip_with_port},
-};
-
-const DEFAULT_PORT: u16 = 8448;
-
-#[derive(Clone, Debug)]
-pub(crate) struct ActualDest {
-	pub(crate) dest: FedDest,
-	pub(crate) host: String,
-}
-
-impl ActualDest {
-	#[inline]
-	pub(crate) fn string(&self) -> String { self.dest.https_string() }
-}
-
-impl super::Service {
-	#[tracing::instrument(skip_all, level = "debug", name = "resolve")]
-	pub(crate) async fn get_actual_dest(&self, server_name: &ServerName) -> Result<ActualDest> {
-		let (CachedDest { dest, host, .. }, _cached) =
-			self.lookup_actual_dest(server_name).await?;
-
-		Ok(ActualDest { dest, host })
-	}
-
-	pub(crate) async fn lookup_actual_dest(
-		&self,
-		server_name: &ServerName,
-	) -> Result<(CachedDest, bool)> {
-		if let Ok(result) = self.cache.get_destination(server_name).await {
-			return Ok((result, true));
-		}
-
-		let _dedup = self.resolving.lock(server_name.as_str());
-		if let Ok(result) = self.cache.get_destination(server_name).await {
-			return Ok((result, true));
-		}
-
-		self.resolve_actual_dest(server_name, true)
-			.inspect_ok(|result| self.cache.set_destination(server_name, result))
-			.map_ok(|result| (result, false))
-			.boxed()
-			.await
-	}
-
-	/// Returns: `actual_destination` + `Host` http header
-	#[tracing::instrument(name = "actual", level = "debug", skip(self, cache))]
-	pub async fn resolve_actual_dest(
-		&self,
-		dest: &ServerName,
-		cache: bool,
-	) -> Result<CachedDest> {
-		debug!(
-			dest = %dest,
-			cache = %cache,
-			"Resolving server name and port"
-		);
-		// Ensure dest is a valid connection endpoint
-		self.validate_dest(dest)?;
-
-		// Clippy believes this can be a clone, however we are actually converting
-		// ServerName to String
-		#[allow(clippy::implicit_clone)]
-		let mut host_header = dest.to_string().to_owned();
-		let actual_dest = self
-			.resolve_server_name(dest, cache, &mut host_header)
-			.await?;
-
-		host_header = ensure_host_has_port(&host_header).to_string();
-
-		debug!(
-			dest = %dest,
-			actual_dest = %actual_dest,
-			host = %host_header,
-			"Finished resolving server name"
-		);
-		Ok(CachedDest {
-			dest: actual_dest,
-			host: host_header,
-			expire: CachedDest::default_expire(),
-		})
-	}
-
-	/// Performs the server resolution steps as per the specification:
-	/// <https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names>
-	async fn resolve_server_name(
-		&self,
-		dest: &ServerName,
-		cache: bool,
-		host: &mut String,
-	) -> Result<FedDest> {
-		// 1. If `dest` is an IP, use it directly. If a port is provided as well
-		//    (IP:port socket pair) use that, otherwise default to port 8448
-		if let Some(fed_dest) = get_ip_with_port(dest.as_str()) {
-			debug!("1: IP literal with provided or default port");
-			return Ok(fed_dest);
-		}
-
-		// 2. If `dest` is a hostname and has a provided port (format of `host:port`),
-		//    resolve the hostname to an IP address and connect it and the provided port
-		if dest.as_str().contains(':') {
-			return self.resolve_2_host_port(dest, cache).await;
-		}
-
-		// Pre-resolve IP? Unsure what overrides exactly do, system is due to be removed
-		// either way https://matrix.to/#/!da26JtAjE6APGLnX8ncWsvc-skF2KQZ9Nw_MbNpYD2k/%24_hq6JP0JXANbMTMPdV64iZbgbsZdhy92M5ndDYGy6No
-		self.conditional_query_and_cache(dest.as_str(), DEFAULT_PORT, true)
-			.await?;
-
-		// Ensure server is running (not shutting down) before continuing resolution
-		self.services.server.check_running()?;
-
-		// 3. If `dest` is a hostname with no port, send GET to `https://<dest>/.well-known/matrix/server`.
-		//    If invalid JSON (throws error), skip to step 4. Otherwise, parse
-		//    `delegated` as `<hostname>[:<port>]` and...
-		if let Some(delegated) = self.request_well_known(dest.as_str()).await? {
-			return self.resolve_3_well_known(host, cache, delegated).await;
-		}
-
-		// 4. if .well-known errored, perform SRV (see 3.3)
-		if let Some(overrider) = self.query_srv_record(dest.as_str()).await? {
-			return self.resolve_4_srv_lookup(host, cache, overrider).await;
-		}
-
-		// 5. if .well-known errored and no SRV exists, resolve IP and connect on
-		//    default port (8448)
-		self.resolve_5_direct(dest, cache).await
-	}
-
-	/// Parse a host:port socket pair into separate parts, and resolve the
-	/// hostname into an IP address
-	async fn resolve_2_host_port(&self, dest: &ServerName, cache: bool) -> Result<FedDest> {
-		debug!("2: Hostname with included port");
-		let (host, port) = dest.as_str().split_once(':').unwrap();
-
-		self.conditional_query_and_cache(
-			host,
-			port.parse::<u16>().unwrap_or(DEFAULT_PORT),
-			cache,
-		)
-		.await?;
-
-		Ok(FedDest::Named(
-			host.to_owned(),
-			port.try_into().unwrap_or_else(|_| FedDest::default_port()),
-		))
-	}
-
-	async fn resolve_3_well_known(
-		&self,
-		host: &mut String,
-		cache: bool,
-		delegated: String,
-	) -> Result<FedDest> {
-		debug!("3: A .well-known file is available");
-		*host = add_port_to_hostname(&delegated).uri_string();
-
-		// 3.1 - If <delegated> is IP:port, connect to that,
-		//       or IP with default port if no port provided (8448)
-		if let Some(host_and_port) = get_ip_with_port(&delegated) {
-			debug!("3.1: IP with port in .well-known file");
-			return Ok(host_and_port);
-		}
-
-		// 3.2 - If <delegated> is hostname:port, lookup IP for hostname and connect
-		if delegated.contains(':') {
-			return self.resolve_3_2_hostname_port(cache, &delegated).await;
-		}
-
-		// 3.3 - If <delegated> is not an IP and there is no port, lookup SRV
-		// `_matrix._tcp.<delegated>` (which may provide a new hostname + port to use,
-		// see steps 3.1 and 3.2)
-		trace!("Delegated hostname has no port, querying SRV");
-		if let Some(overrider) = self.query_srv_record(&delegated).await? {
-			return self.resolve_3_3_use_srv(cache, &delegated, overrider).await;
-		}
-
-		self.resolve_3_4_use_default_port(cache, delegated).await
-	}
-
-	async fn resolve_3_2_hostname_port(&self, cache: bool, delegated: &str) -> Result<FedDest> {
-		debug!("3.2: Hostname with port in .well-known file");
-		let (host, port) = &delegated.split_once(':').unwrap();
-		self.conditional_query_and_cache(
-			host,
-			port.parse::<u16>().unwrap_or(DEFAULT_PORT),
-			cache,
-		)
-		.await?;
-
-		trace!("Successfully resolved IP for {delegated}");
-		Ok(FedDest::Named(
-			host.to_owned().to_owned(),
-			port.to_owned()
-				.try_into()
-				.unwrap_or_else(|_| FedDest::default_port()),
-		))
-	}
-
-	async fn resolve_3_3_use_srv(
-		&self,
-		cache: bool,
-		delegated: &String,
-		overrider: FedDest,
-	) -> Result<FedDest> {
-		debug!("3.3: SRV lookup successful");
-
-		let force_port = overrider.port();
-		self.conditional_query_and_cache_override(
-			delegated,
-			&overrider.hostname(),
-			force_port.unwrap_or(DEFAULT_PORT),
-			cache,
-		)
-		.await?;
-
-		if let Some(port) = force_port {
-			return Ok(FedDest::Named(
-				delegated.to_owned(),
-				format!(":{port}")
-					.as_str()
-					.try_into()
-					.unwrap_or_else(|_| FedDest::default_port()),
-			));
-		}
-
-		Ok(add_port_to_hostname(delegated))
-	}
-
-	async fn resolve_3_4_use_default_port(
-		&self,
-		cache: bool,
-		delegated: String,
-	) -> Result<FedDest> {
-		debug!("3.4: No SRV records found, use the hostname from .well-known with default port");
-		self.conditional_query_and_cache(&delegated, DEFAULT_PORT, cache)
-			.await?;
-		Ok(add_port_to_hostname(&delegated))
-	}
-
-	async fn resolve_4_srv_lookup(
-		&self,
-		host: &str,
-		cache: bool,
-		overrider: FedDest,
-	) -> Result<FedDest> {
-		debug!("4: No .well-known; SRV record found");
-		let force_port = overrider.port();
-		self.conditional_query_and_cache_override(
-			host,
-			&overrider.hostname(),
-			force_port.unwrap_or(DEFAULT_PORT),
-			cache,
-		)
-		.await?;
-
-		if let Some(port) = force_port {
-			let port = format!(":{port}");
-
-			return Ok(FedDest::Named(
-				host.to_owned(),
-				PortString::from(port.as_str()).unwrap_or_else(|_| FedDest::default_port()),
-			));
-		}
-
-		Ok(add_port_to_hostname(host))
-	}
-
-	async fn resolve_5_direct(&self, dest: &ServerName, cache: bool) -> Result<FedDest> {
-		debug!("5: No port provided and no SRV record found");
-		self.conditional_query_and_cache(dest.as_str(), DEFAULT_PORT, cache)
-			.await?;
-
-		Ok(add_port_to_hostname(dest.as_str()))
-	}
-
-	#[inline]
-	async fn conditional_query_and_cache(
-		&self,
-		hostname: &str,
-		port: u16,
-		cache: bool,
-	) -> Result {
-		self.conditional_query_and_cache_override(hostname, hostname, port, cache)
-			.await
-	}
-
-	#[inline]
-	async fn conditional_query_and_cache_override(
-		&self,
-		untername: &str,
-		hostname: &str,
-		port: u16,
-		cache: bool,
-	) -> Result {
-		if !cache {
-			return Ok(());
-		}
-
-		if self.cache.has_override(untername).await {
-			return Ok(());
-		}
-
-		self.query_and_cache_override(untername, hostname, port)
-			.await
-	}
-
-	#[tracing::instrument(name = "ip", level = "debug", skip(self))]
-	async fn query_and_cache_override(
-		&self,
-		untername: &'_ str,
-		hostname: &'_ str,
-		port: u16,
-	) -> Result {
-		self.services.server.check_running()?;
-
-		debug!("querying IP for {untername:?} ({hostname:?}:{port})");
-		match self.resolver.resolver.lookup_ip(hostname.to_owned()).await {
-			| Err(e) => Self::handle_resolve_error(&e, hostname),
-			| Ok(override_ip) => {
-				self.cache.set_override(untername, &CachedOverride {
-					ips: override_ip.into_iter().take(MAX_IPS).collect(),
-					port,
-					expire: CachedOverride::default_expire(),
-					overriding: (hostname != untername)
-						.then_some(hostname.into())
-						.inspect(|_| debug_info!("{untername:?} overridden by {hostname:?}")),
-				});
-
-				Ok(())
-			},
-		}
-	}
-
-	#[tracing::instrument(name = "srv", level = "debug", skip(self))]
-	async fn query_srv_record(&self, hostname: &'_ str) -> Result<Option<FedDest>> {
-		let hostnames =
-			[format!("_matrix-fed._tcp.{hostname}."), format!("_matrix._tcp.{hostname}.")];
-
-		for hostname in hostnames {
-			self.services.server.check_running()?;
-
-			debug!("querying SRV for {hostname:?}");
-			let hostname = hostname.trim_end_matches('.');
-			match self.resolver.resolver.srv_lookup(hostname).await {
-				| Err(e) => Self::handle_resolve_error(&e, hostname)?,
-				| Ok(result) => {
-					return Ok(result.answers().iter().next().map(|result| {
-						let data = result.try_borrow::<SRV>().expect("should be SRV response");
-
-						FedDest::Named(
-							data.data()
-								.target
-								.to_string()
-								.trim_end_matches('.')
-								.to_owned(),
-							format!(":{}", data.data().port)
-								.as_str()
-								.try_into()
-								.unwrap_or_else(|_| FedDest::default_port()),
-						)
-					}));
-				},
-			}
-		}
-
-		Ok(None)
-	}
-
-	fn handle_resolve_error(err: &NetError, host: &'_ str) -> Result<()> {
-		match err {
-			| NetError::NoConnections => {
-				error!(
-					"Your DNS server is overloaded and has ran out of connections. It is \
-					 strongly recommended you remediate this issue to ensure proper federation \
-					 connectivity."
-				);
-
-				Err!(error!(%host, "DNS error: {err}"))
-			},
-			| NetError::Timeout => Err!(error!(%host, "DNS query timed out")),
-			| NetError::Dns(DnsError::NoRecordsFound(..)) => {
-				// Raise to debug_warn if we can find out the result wasn't from cache
-				debug!(%host, "No DNS records found: {err}");
-				Ok(())
-			},
-			| _ => Err!(error!(%host, "DNS error: {err}")),
-		}
-	}
-
-	/// Ensure `dest` is a valid destination (valid ip if it is an IP), and not
-	/// ourselves (unless in config)
-	fn validate_dest(&self, dest: &ServerName) -> Result<()> {
-		if dest == self.services.server.name && !self.services.server.config.federation_loopback {
-			return Err!("Won't send federation request to ourselves");
-		}
-
-		if dest.is_ip_literal() || IPAddress::is_valid(dest.host()) {
-			self.validate_dest_ip_literal(dest)?;
-		}
-
-		debug!(dest = %dest, "Valid destination for resolution");
-		Ok(())
-	}
-
-	fn validate_dest_ip_literal(&self, dest: &ServerName) -> Result<()> {
-		trace!("Destination is an IP literal, checking against IP range denylist.",);
-		debug_assert!(
-			dest.is_ip_literal() || !IPAddress::is_valid(dest.host()),
-			"Destination is not an IP literal."
-		);
-		let ip = IPAddress::parse(dest.host()).map_err(|e| {
-			err!(BadServerResponse(debug_error!("Failed to parse IP literal from string: {e}")))
-		})?;
-
-		self.validate_ip(&ip)?;
-
-		Ok(())
-	}
-
-	pub(crate) fn validate_ip(&self, ip: &IPAddress) -> Result<()> {
-		if !self.services.client.valid_cidr_range(ip) {
-			return Err!(BadServerResponse("Not allowed to send requests to this IP"));
-		}
-
-		Ok(())
-	}
-}
diff --git c/src/service/resolver/cache.rs i/src/service/resolver/cache.rs
index 6bad6402d..e775a72ac 100644
--- c/src/service/resolver/cache.rs
+++ i/src/service/resolver/cache.rs
@@ -4,7 +4,7 @@
 	Result,
 	arrayvec::ArrayVec,
 	at, err, implement,
-	utils::{math::Expected, rand, stream::TryIgnore},
+	utils::{math::Expected, stream::TryIgnore},
 };
 use database::{Cbor, Deserialized, Map};
 use futures::{Stream, StreamExt, future::join};
@@ -127,11 +127,6 @@ impl CachedDest {
 	#[must_use]
 	pub fn valid(&self) -> bool { self.expire > SystemTime::now() }

-	#[must_use]
-	pub(crate) fn default_expire() -> SystemTime {
-		rand::time_from_now_secs(60 * 60 * 18..60 * 60 * 36)
-	}
-
 	#[inline]
 	#[must_use]
 	pub fn size(&self) -> usize {
@@ -147,11 +142,6 @@ impl CachedOverride {
 	#[must_use]
 	pub fn valid(&self) -> bool { self.expire > SystemTime::now() }

-	#[must_use]
-	pub(crate) fn default_expire() -> SystemTime {
-		rand::time_from_now_secs(60 * 60 * 6..60 * 60 * 12)
-	}
-
 	#[inline]
 	#[must_use]
 	pub fn size(&self) -> usize { size_of_val(self) }
diff --git c/src/service/resolver/fed.rs i/src/service/resolver/fed.rs
index 83601a98a..f8068f596 100644
--- c/src/service/resolver/fed.rs
+++ i/src/service/resolver/fed.rs
@@ -1,8 +1,4 @@
-use std::{
-	borrow::Cow,
-	fmt,
-	net::{IpAddr, SocketAddr},
-};
+use std::{fmt, net::SocketAddr};

 use conduwuit::{arrayvec::ArrayString, utils::math::Expected};
 use serde::{Deserialize, Serialize};
@@ -18,50 +14,7 @@ pub enum FedDest {

 const DEFAULT_PORT: &str = ":8448";

-/// Attempt to parse `dest_str` as either an IP:port socket pair or as a plain
-/// IP (adding the default port), returning `None` if dest_str is neither a
-/// socket pair nor a plain IP.
-pub(crate) fn get_ip_with_port(dest_str: &str) -> Option<FedDest> {
-	if let Ok(dest) = dest_str.parse::<SocketAddr>() {
-		Some(FedDest::Literal(dest))
-	} else if let Ok(ip_addr) = dest_str.parse::<IpAddr>() {
-		Some(FedDest::Literal(SocketAddr::new(ip_addr, 8448)))
-	} else {
-		None
-	}
-}
-
-/// Convert a `dest` string with or without port into a FedDest with either
-/// the provided port (if host:port format) or the default port (8448)
-pub(crate) fn add_port_to_hostname(dest: &str) -> FedDest {
-	let (host, port) = match dest.find(':') {
-		| None => (dest, DEFAULT_PORT),
-		| Some(pos) => dest.split_at(pos),
-	};
-
-	FedDest::Named(
-		host.to_owned(),
-		PortString::from(port).unwrap_or_else(|_| FedDest::default_port()),
-	)
-}
-
-/// Ensure `host` always has a port
-///
-/// `get_ip_with_port` returns `None` if `host` isn't an IP:port string or plain
-/// IP, in which case `add_port_to_hostname` adds it instead
-#[inline]
-pub(crate) fn ensure_host_has_port(host: &str) -> FedDest {
-	get_ip_with_port(host).unwrap_or_else(|| add_port_to_hostname(host))
-}
-
 impl FedDest {
-	pub(crate) fn https_string(&self) -> String {
-		match self {
-			| Self::Literal(addr) => format!("https://{addr}"),
-			| Self::Named(host, port) => format!("https://{host}{port}"),
-		}
-	}
-
 	pub(crate) fn uri_string(&self) -> String {
 		match self {
 			| Self::Literal(addr) => addr.to_string(),
@@ -69,23 +22,6 @@ pub(crate) fn uri_string(&self) -> String {
 		}
 	}

-	#[inline]
-	pub(crate) fn hostname(&self) -> Cow<'_, str> {
-		match &self {
-			| Self::Literal(addr) => addr.ip().to_string().into(),
-			| Self::Named(host, _) => host.into(),
-		}
-	}
-
-	#[inline]
-	#[allow(clippy::string_slice)]
-	pub(crate) fn port(&self) -> Option<u16> {
-		match &self {
-			| Self::Literal(addr) => Some(addr.port()),
-			| Self::Named(_, port) => port[1..].parse().ok(),
-		}
-	}
-
 	#[inline]
 	#[must_use]
 	pub fn default_port() -> PortString {
diff --git c/src/service/resolver/mod.rs i/src/service/resolver/mod.rs
index c513cec9a..c24b8ba60 100644
--- c/src/service/resolver/mod.rs
+++ i/src/service/resolver/mod.rs
@@ -1,33 +1,31 @@
-pub mod actual;
 pub mod cache;
 mod dns;
 pub mod fed;
-#[cfg(test)]
-mod tests;
-mod well_known;

 use std::sync::Arc;

 use async_trait::async_trait;
-use conduwuit::{Result, Server, arrayvec::ArrayString, utils::MutexMap};
+use conduwuit::{Err, Result, implement};
+use ipaddress::IPAddress;
+use resolvematrix::server::MatrixResolver;

 use self::{cache::Cache, dns::Resolver};
 use crate::{Dep, client};

 pub struct Service {
-	pub cache: Arc<Cache>,
-	pub resolver: Arc<Resolver>,
-	resolving: Resolving,
+	pub resolver: MatrixResolver,
+	pub dns: Dns,
 	services: Services,
 }

 struct Services {
-	server: Arc<Server>,
 	client: Dep<client::Service>,
 }

-type Resolving = MutexMap<NameBuf, ()>;
-type NameBuf = ArrayString<256>;
+pub struct Dns {
+	pub cache: Arc<Cache>,
+	pub resolver: Arc<Resolver>,
+}

 #[async_trait]
 impl crate::Service for Service {
@@ -35,20 +33,31 @@ impl crate::Service for Service {
 	fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 		let cache = Cache::new(&args);
 		Ok(Arc::new(Self {
-			cache: cache.clone(),
-			resolver: Resolver::build(args.server, cache)?,
-			resolving: MutexMap::new(),
+			resolver: MatrixResolver::new()?,
+			dns: Dns {
+				cache: cache.clone(),
+				resolver: Resolver::build(args.server, cache)?,
+			},
 			services: Services {
-				server: args.server.clone(),
 				client: args.depend::<client::Service>("client"),
 			},
 		}))
 	}

 	async fn clear_cache(&self) {
-		self.resolver.clear_cache();
-		self.cache.clear().await;
+		// No ability to clean resolvematrix cache at the moment
+		self.dns.resolver.clear_cache();
+		self.dns.cache.clear().await;
 	}

-	fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
+	fn name(&self) -> &str { crate::service::make_name(module_path!()) }
+}
+
+#[implement(Service)]
+pub fn validate_ip(&self, ip: &IPAddress) -> Result<()> {
+	if !self.services.client.valid_cidr_range(ip) {
+		return Err!(BadServerResponse("Not allowed to send requests to this IP"));
+	}
+
+	Ok(())
 }
diff --git c/src/service/resolver/tests.rs i/src/service/resolver/tests.rs
deleted file mode 100644
index 068e08bd0..000000000
--- c/src/service/resolver/tests.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use super::fed::{FedDest, add_port_to_hostname, get_ip_with_port};
-
-#[test]
-fn ips_get_default_ports() {
-	assert_eq!(
-		get_ip_with_port("1.1.1.1"),
-		Some(FedDest::Literal("1.1.1.1:8448".parse().unwrap()))
-	);
-	assert_eq!(
-		get_ip_with_port("dead:beef::"),
-		Some(FedDest::Literal("[dead:beef::]:8448".parse().unwrap()))
-	);
-}
-
-#[test]
-fn ips_keep_custom_ports() {
-	assert_eq!(
-		get_ip_with_port("1.1.1.1:1234"),
-		Some(FedDest::Literal("1.1.1.1:1234".parse().unwrap()))
-	);
-	assert_eq!(
-		get_ip_with_port("[dead::beef]:8933"),
-		Some(FedDest::Literal("[dead::beef]:8933".parse().unwrap()))
-	);
-}
-
-#[test]
-fn hostnames_get_default_ports() {
-	assert_eq!(
-		add_port_to_hostname("example.com"),
-		FedDest::Named(String::from("example.com"), ":8448".try_into().unwrap())
-	);
-}
-
-#[test]
-fn hostnames_keep_custom_ports() {
-	assert_eq!(
-		add_port_to_hostname("example.com:1337"),
-		FedDest::Named(String::from("example.com"), ":1337".try_into().unwrap())
-	);
-}
diff --git c/src/service/resolver/well_known.rs i/src/service/resolver/well_known.rs
deleted file mode 100644
index 237c5cd09..000000000
--- c/src/service/resolver/well_known.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-use conduwuit::{
-	Result, debug, debug_error, debug_info, implement, trace, utils::response::LimitReadExt,
-};
-use ruma::ServerName;
-
-#[implement(super::Service)]
-#[tracing::instrument(name = "well-known", level = "debug", skip(self, dest))]
-pub(super) async fn request_well_known(&self, dest: &str) -> Result<Option<String>> {
-	trace!("Requesting well known for {dest}");
-	let response = self
-		.services
-		.client
-		.well_known
-		.get(format!("https://{dest}/.well-known/matrix/server"))
-		.send()
-		.await;
-
-	trace!("response: {response:?}");
-	if let Err(e) = &response {
-		debug!("error: {e:?}");
-		return Ok(None);
-	}
-
-	let response = response?;
-	if !response.status().is_success() {
-		debug!("response not 2XX");
-		return Ok(None);
-	}
-
-	let Ok(text) = response.limit_read_text(8192).await else {
-		debug!("failed to read well-known response (too large or non-text content)");
-		return Ok(None);
-	};
-	trace!("response text: {text:?}");
-
-	let body: serde_json::Value = serde_json::from_str(&text).unwrap_or_default();
-
-	let m_server = body
-		.get("m.server")
-		.unwrap_or(&serde_json::Value::Null)
-		.as_str()
-		.unwrap_or_default();
-
-	if ServerName::parse(m_server).is_err() {
-		debug_error!("response content missing or invalid");
-		return Ok(None);
-	}
-
-	debug_info!("{dest:?} found at {m_server:?}");
-	Ok(Some(m_server.to_owned()))
-}

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	src/admin/debug/commands.rs
#	src/admin/query/resolver.rs
#	src/service/Cargo.toml
#	src/service/client/mod.rs
#	src/service/federation/execute.rs
#	src/service/resolver/cache.rs
#	src/service/resolver/well_known.rs

diff --git c/Cargo.toml i/Cargo.toml
index 09e2f93cb..f89a5e010 100644
--- c/Cargo.toml
+++ i/Cargo.toml
@@ -560,6 +560,9 @@ features = ["std"]
 [workspace.dependencies.nonzero_ext]
 version = "0.3.0"

+[workspace.dependencies.resolvematrix]
+version = "0.1.0"
+
 [workspace.dependencies.serde_urlencoded]
 version = "0.7.1"

diff --git c/src/admin/Cargo.toml i/src/admin/Cargo.toml
index 4afed12b4..1f82978a4 100644
--- c/src/admin/Cargo.toml
+++ i/src/admin/Cargo.toml
@@ -92,6 +92,7 @@ serde-saphyr.workspace = true
 tokio.workspace = true
 tracing-subscriber.workspace = true
 tracing.workspace = true
+resolvematrix.workspace = true

 [lints]
 workspace = true
diff --git c/src/admin/debug/commands.rs i/src/admin/debug/commands.rs
index d1e5c2544..290189859 100644
--- c/src/admin/debug/commands.rs
+++ i/src/admin/debug/commands.rs
@@ -20,6 +20,7 @@
 };
 use futures::{FutureExt, StreamExt, TryStreamExt};
 use lettre::message::Mailbox;
+use resolvematrix::server::{MatrixResolver, ResolvedDestination};
 use ruma::{
 	CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId,
 	OwnedRoomOrAliasId, OwnedServerName, RoomId, RoomVersionId, UInt,
@@ -1005,15 +1006,22 @@ pub(super) async fn resolve_true_destination(
 			);
 		}

-		let actual = self
-			.services
-			.resolver
-			.resolve_actual_dest(&server_name, !no_cache)
-			.await?;
+	let resolver: &MatrixResolver = if no_cache {
+		&MatrixResolver::new()?
+	} else {
+		&self.services.resolver.resolver
+	};

-		let msg = format!("Destination: {}\nHostname URI: {}", actual.dest, actual.host);
-		self.write_str(&msg).await
-	}
+	let actual = resolver.resolve_server(&server_name.as_str()).await?;
+
+	let destination = match actual.destination {
+		| ResolvedDestination::Literal(addr) => addr.to_string(),
+		| ResolvedDestination::Named(host, port) => format!("{host}:{port}"),
+	};
+
+	let msg = format!("Destination: {}\nHostname URI (SNI): {}", destination, actual.host);
+	self.write_str(&msg).await
+}

 	pub(super) async fn memory_stats(&self, opts: Option<String>) -> Result {
 		const OPTS: &str = "abcdefghijklmnopqrstuvwxyz";
diff --git c/src/admin/query/resolver.rs i/src/admin/query/resolver.rs
index 7e5a4b40d..4a88650f8 100644
--- c/src/admin/query/resolver.rs
+++ i/src/admin/query/resolver.rs
@@ -46,7 +46,7 @@ async fn destinations_cache(&self, server_name: Option<OwnedServerName>) -> Resu
 		writeln!(self, "| Server Name | Destination | Hostname | Expires |").await?;
 		writeln!(self, "| ----------- | ----------- | -------- | ------- |").await?;

-		let mut destinations = self.services.resolver.cache.destinations().boxed();
+	    let mut destinations = self.services.resolver.dns.cache.destinations().boxed();

 		while let Some((name, CachedDest { dest, host, expire })) = destinations.next().await {
 			if let Some(server_name) = server_name.as_ref() {
@@ -69,7 +69,7 @@ async fn overrides_cache(&self, server_name: Option<String>) -> Result {
 		writeln!(self, "| Server Name | IP  | Port | Expires | Overriding |").await?;
 		writeln!(self, "| ----------- | --- | ----:| ------- | ---------- |").await?;

-		let mut overrides = self.services.resolver.cache.overrides().boxed();
+		let mut overrides = self.services.resolver.dns.cache.overrides().boxed();

 		while let Some((name, CachedOverride { ips, port, expire, overriding })) =
 			overrides.next().await
@@ -92,11 +92,11 @@ async fn overrides_cache(&self, server_name: Option<String>) -> Result {

 	async fn flush_cache(&self, name: Option<OwnedServerName>, all: bool) -> Result {
 		if all {
-			self.services.resolver.cache.clear().await;
+			self.services.resolver.dns.cache.clear().await;
 			writeln!(self, "Resolver caches cleared!").await
 		} else if let Some(name) = name {
-			self.services.resolver.cache.del_destination(&name);
-			self.services.resolver.cache.del_override(&name);
+			self.services.resolver.dns.cache.del_destination(&name);
+			self.services.resolver.dns.cache.del_override(&name);
 			self.write_str(&format!("Cleared {name} from resolver caches!"))
 				.await
 		} else {
diff --git c/src/core/Cargo.toml i/src/core/Cargo.toml
index 093b50f71..d99184b9d 100644
--- c/src/core/Cargo.toml
+++ i/src/core/Cargo.toml
@@ -117,6 +117,7 @@ url.workspace = true
 parking_lot.workspace = true
 lock_api.workspace = true
 hyper-util.workspace = true
+resolvematrix.workspace = true

 [target.'cfg(unix)'.dependencies]
 nix.workspace = true
diff --git c/src/core/error/mod.rs i/src/core/error/mod.rs
index d61867b01..813324912 100644
--- c/src/core/error/mod.rs
+++ i/src/core/error/mod.rs
@@ -87,6 +87,8 @@ pub enum Error {
 	YamlDe(#[from] serde_saphyr::Error),
 	#[error(transparent)]
 	YamlSer(#[from] serde_saphyr::ser_error::Error),
+	#[error(transparent)]
+	ResolveServer(#[from] resolvematrix::server::ResolveServerError),

 	// ruma/conduwuit
 	#[error("Arithmetic operation failed: {0}")]
diff --git c/src/service/Cargo.toml i/src/service/Cargo.toml
index e302ff6c9..923fef2cb 100644
--- c/src/service/Cargo.toml
+++ i/src/service/Cargo.toml
@@ -119,6 +119,7 @@ recaptcha-verify = { version = "0.2.0", default-features = false }
 reqwest_recaptcha = { package = "reqwest", version = "0.12.28", default-features = false, features = ["rustls-tls-native-roots-no-provider"]  } # As long as recaptcha-verify's reqwest is outdated
 yansi.workspace = true
 lettre.workspace = true
+resolvematrix.workspace = true
 serde_urlencoded.workspace = true

 [target.'cfg(all(unix, target_os = "linux"))'.dependencies]
diff --git c/src/service/client/mod.rs i/src/service/client/mod.rs
index b4c645ba2..4a299fee3 100644
--- c/src/service/client/mod.rs
+++ i/src/service/client/mod.rs
@@ -43,7 +43,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {

 		Ok(Arc::new(Self {
 			default: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.build()?,

 			url_preview: base(config)
@@ -51,19 +51,19 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 					builder_interface(builder, url_preview_bind_iface.as_deref())
 				})?
 				.local_address(url_preview_bind_addr)
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.timeout(Duration::from_secs(config.url_preview_timeout))
 				.redirect(redirect::Policy::limited(3))
 				.user_agent(url_preview_user_agent)
 				.build()?,

 			extern_media: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.redirect(redirect::Policy::limited(3))
 				.build()?,

 			well_known: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.connect_timeout(Duration::from_secs(config.well_known_conn_timeout))
 				.read_timeout(Duration::from_secs(config.well_known_timeout))
 				.timeout(Duration::from_secs(config.well_known_timeout))
@@ -72,7 +72,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			federation: base(config)?
-				.dns_resolver(resolver.resolver.hooked.clone())
+				.dns_resolver(resolver.dns.resolver.hooked.clone())
 				.connect_timeout(Duration::from_secs(config.federation_conn_timeout))
 				.read_timeout(Duration::from_secs(config.federation_timeout))
 				.timeout(Duration::from_secs(
@@ -86,7 +86,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			federation_slow: base(config)?
-				.dns_resolver(resolver.resolver.hooked.clone())
+				.dns_resolver(resolver.dns.resolver.hooked.clone())
 				.connect_timeout(Duration::from_secs(config.federation_conn_timeout))
 				.read_timeout(Duration::from_secs(config.federation_timeout.saturating_mul(6)))
 				.timeout(Duration::from_secs(
@@ -100,7 +100,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			sender: base(config)?
-				.dns_resolver(resolver.resolver.hooked.clone())
+				.dns_resolver(resolver.dns.resolver.hooked.clone())
 				.connect_timeout(Duration::from_secs(config.federation_conn_timeout))
 				.read_timeout(Duration::from_secs(config.sender_timeout))
 				.timeout(Duration::from_secs(config.sender_timeout))
@@ -110,7 +110,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			appservice: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.connect_timeout(Duration::from_secs(5))
 				.read_timeout(Duration::from_secs(config.appservice_timeout))
 				.timeout(Duration::from_secs(config.appservice_timeout))
@@ -120,7 +120,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 				.build()?,

 			pusher: base(config)?
-				.dns_resolver(resolver.resolver.clone())
+				.dns_resolver(resolver.dns.resolver.clone())
 				.connect_timeout(Duration::from_secs(config.pusher_conn_timeout))
 				.timeout(Duration::from_secs(config.pusher_timeout))
 				.pool_max_idle_per_host(1)
diff --git c/src/service/federation/execute.rs i/src/service/federation/execute.rs
index 70bef2f0e..d843f9ad4 100644
--- c/src/service/federation/execute.rs
+++ i/src/service/federation/execute.rs
@@ -7,6 +7,7 @@
 };
 use ipaddress::IPAddress;
 use reqwest::{Client, Method, Request, Response, Url};
+use resolvematrix::resolution::Resolution;
 use ruma::{
 	ServerName,
 	api::{
@@ -150,7 +151,7 @@ pub async fn execute_on<'i, T, PathBuilderInput>(
 	async fn perform<T>(
 		&self,
 		dest: &ServerName,
-		actual: &ActualDest,
+		actual: &Resolution,
 		request: Request,
 		client: &Client,
 	) -> Result<T::IncomingResponse>
@@ -198,7 +199,7 @@ fn validate_url(&self, url: &Url) -> Result<()> {
 	async fn handle_response<T>(
 		&self,
 		dest: &ServerName,
-		actual: &ActualDest,
+		actual: &Resolution,
 		method: &Method,
 		url: &Url,
 		response: Response,
@@ -231,7 +232,7 @@ async fn handle_response<T>(

 async fn into_http_response(
 	dest: &ServerName,
-	actual: &ActualDest,
+	actual: &Resolution,
 	method: &Method,
 	url: &Url,
 	mut response: Response,
@@ -243,7 +244,7 @@ async fn into_http_response(
 		request_url = %url,
 		response_url = %response.url(),
 		"Received response from {}",
-		actual.string(),
+		actual.base_url(),
 	);

 	let mut http_response_builder = http::Response::builder()
@@ -280,7 +281,7 @@ async fn into_http_response(
 }

 fn handle_error(
-	actual: &ActualDest,
+	actual: &Resolution,
 	method: &Method,
 	url: &Url,
 	mut e: reqwest::Error,
diff --git c/src/service/resolver/actual.rs i/src/service/resolver/actual.rs
index 1ca3b595c..e69de29bb 100644
--- c/src/service/resolver/actual.rs
+++ i/src/service/resolver/actual.rs
@@ -1,441 +0,0 @@
-use std::fmt::Debug;
-
-use conduwuit::{Err, Result, debug, debug_info, err, error, trace};
-use futures::{FutureExt, TryFutureExt};
-use hickory_resolver::{
-	net::{DnsError, NetError},
-	proto::rr::rdata::SRV,
-};
-use ipaddress::IPAddress;
-use ruma::ServerName;
-
-use super::{
-	cache::{CachedDest, CachedOverride, MAX_IPS},
-	fed::{FedDest, PortString, add_port_to_hostname, ensure_host_has_port, get_ip_with_port},
-};
-
-const DEFAULT_PORT: u16 = 8448;
-
-#[derive(Clone, Debug)]
-pub(crate) struct ActualDest {
-	pub(crate) dest: FedDest,
-	pub(crate) host: String,
-}
-
-impl ActualDest {
-	#[inline]
-	pub(crate) fn string(&self) -> String { self.dest.https_string() }
-}
-
-impl super::Service {
-	#[tracing::instrument(skip_all, level = "debug", name = "resolve")]
-	pub(crate) async fn get_actual_dest(&self, server_name: &ServerName) -> Result<ActualDest> {
-		let (CachedDest { dest, host, .. }, _cached) =
-			self.lookup_actual_dest(server_name).await?;
-
-		Ok(ActualDest { dest, host })
-	}
-
-	pub(crate) async fn lookup_actual_dest(
-		&self,
-		server_name: &ServerName,
-	) -> Result<(CachedDest, bool)> {
-		if let Ok(result) = self.cache.get_destination(server_name).await {
-			return Ok((result, true));
-		}
-
-		let _dedup = self.resolving.lock(server_name.as_str());
-		if let Ok(result) = self.cache.get_destination(server_name).await {
-			return Ok((result, true));
-		}
-
-		self.resolve_actual_dest(server_name, true)
-			.inspect_ok(|result| self.cache.set_destination(server_name, result))
-			.map_ok(|result| (result, false))
-			.boxed()
-			.await
-	}
-
-	/// Returns: `actual_destination` + `Host` http header
-	#[tracing::instrument(name = "actual", level = "debug", skip(self, cache))]
-	pub async fn resolve_actual_dest(
-		&self,
-		dest: &ServerName,
-		cache: bool,
-	) -> Result<CachedDest> {
-		debug!(
-			dest = %dest,
-			cache = %cache,
-			"Resolving server name and port"
-		);
-		// Ensure dest is a valid connection endpoint
-		self.validate_dest(dest)?;
-
-		// Clippy believes this can be a clone, however we are actually converting
-		// ServerName to String
-		#[allow(clippy::implicit_clone)]
-		let mut host_header = dest.to_string().to_owned();
-		let actual_dest = self
-			.resolve_server_name(dest, cache, &mut host_header)
-			.await?;
-
-		host_header = ensure_host_has_port(&host_header).to_string();
-
-		debug!(
-			dest = %dest,
-			actual_dest = %actual_dest,
-			host = %host_header,
-			"Finished resolving server name"
-		);
-		Ok(CachedDest {
-			dest: actual_dest,
-			host: host_header,
-			expire: CachedDest::default_expire(),
-		})
-	}
-
-	/// Performs the server resolution steps as per the specification:
-	/// <https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names>
-	async fn resolve_server_name(
-		&self,
-		dest: &ServerName,
-		cache: bool,
-		host: &mut String,
-	) -> Result<FedDest> {
-		// 1. If `dest` is an IP, use it directly. If a port is provided as well
-		//    (IP:port socket pair) use that, otherwise default to port 8448
-		if let Some(fed_dest) = get_ip_with_port(dest.as_str()) {
-			debug!("1: IP literal with provided or default port");
-			return Ok(fed_dest);
-		}
-
-		// 2. If `dest` is a hostname and has a provided port (format of `host:port`),
-		//    resolve the hostname to an IP address and connect it and the provided port
-		if dest.as_str().contains(':') {
-			return self.resolve_2_host_port(dest, cache).await;
-		}
-
-		// Pre-resolve IP? Unsure what overrides exactly do, system is due to be removed
-		// either way https://matrix.to/#/!da26JtAjE6APGLnX8ncWsvc-skF2KQZ9Nw_MbNpYD2k/%24_hq6JP0JXANbMTMPdV64iZbgbsZdhy92M5ndDYGy6No
-		self.conditional_query_and_cache(dest.as_str(), DEFAULT_PORT, true)
-			.await?;
-
-		// Ensure server is running (not shutting down) before continuing resolution
-		self.services.server.check_running()?;
-
-		// 3. If `dest` is a hostname with no port, send GET to `https://<dest>/.well-known/matrix/server`.
-		//    If invalid JSON (throws error), skip to step 4. Otherwise, parse
-		//    `delegated` as `<hostname>[:<port>]` and...
-		if let Some(delegated) = self.request_well_known(dest.as_str()).await? {
-			return self.resolve_3_well_known(host, cache, delegated).await;
-		}
-
-		// 4. if .well-known errored, perform SRV (see 3.3)
-		if let Some(overrider) = self.query_srv_record(dest.as_str()).await? {
-			return self.resolve_4_srv_lookup(host, cache, overrider).await;
-		}
-
-		// 5. if .well-known errored and no SRV exists, resolve IP and connect on
-		//    default port (8448)
-		self.resolve_5_direct(dest, cache).await
-	}
-
-	/// Parse a host:port socket pair into separate parts, and resolve the
-	/// hostname into an IP address
-	async fn resolve_2_host_port(&self, dest: &ServerName, cache: bool) -> Result<FedDest> {
-		debug!("2: Hostname with included port");
-		let (host, port) = dest.as_str().split_once(':').unwrap();
-
-		self.conditional_query_and_cache(
-			host,
-			port.parse::<u16>().unwrap_or(DEFAULT_PORT),
-			cache,
-		)
-		.await?;
-
-		Ok(FedDest::Named(
-			host.to_owned(),
-			port.try_into().unwrap_or_else(|_| FedDest::default_port()),
-		))
-	}
-
-	async fn resolve_3_well_known(
-		&self,
-		host: &mut String,
-		cache: bool,
-		delegated: String,
-	) -> Result<FedDest> {
-		debug!("3: A .well-known file is available");
-		*host = add_port_to_hostname(&delegated).uri_string();
-
-		// 3.1 - If <delegated> is IP:port, connect to that,
-		//       or IP with default port if no port provided (8448)
-		if let Some(host_and_port) = get_ip_with_port(&delegated) {
-			debug!("3.1: IP with port in .well-known file");
-			return Ok(host_and_port);
-		}
-
-		// 3.2 - If <delegated> is hostname:port, lookup IP for hostname and connect
-		if delegated.contains(':') {
-			return self.resolve_3_2_hostname_port(cache, &delegated).await;
-		}
-
-		// 3.3 - If <delegated> is not an IP and there is no port, lookup SRV
-		// `_matrix._tcp.<delegated>` (which may provide a new hostname + port to use,
-		// see steps 3.1 and 3.2)
-		trace!("Delegated hostname has no port, querying SRV");
-		if let Some(overrider) = self.query_srv_record(&delegated).await? {
-			return self.resolve_3_3_use_srv(cache, &delegated, overrider).await;
-		}
-
-		self.resolve_3_4_use_default_port(cache, delegated).await
-	}
-
-	async fn resolve_3_2_hostname_port(&self, cache: bool, delegated: &str) -> Result<FedDest> {
-		debug!("3.2: Hostname with port in .well-known file");
-		let (host, port) = &delegated.split_once(':').unwrap();
-		self.conditional_query_and_cache(
-			host,
-			port.parse::<u16>().unwrap_or(DEFAULT_PORT),
-			cache,
-		)
-		.await?;
-
-		trace!("Successfully resolved IP for {delegated}");
-		Ok(FedDest::Named(
-			host.to_owned().to_owned(),
-			port.to_owned()
-				.try_into()
-				.unwrap_or_else(|_| FedDest::default_port()),
-		))
-	}
-
-	async fn resolve_3_3_use_srv(
-		&self,
-		cache: bool,
-		delegated: &String,
-		overrider: FedDest,
-	) -> Result<FedDest> {
-		debug!("3.3: SRV lookup successful");
-
-		let force_port = overrider.port();
-		self.conditional_query_and_cache_override(
-			delegated,
-			&overrider.hostname(),
-			force_port.unwrap_or(DEFAULT_PORT),
-			cache,
-		)
-		.await?;
-
-		if let Some(port) = force_port {
-			return Ok(FedDest::Named(
-				delegated.to_owned(),
-				format!(":{port}")
-					.as_str()
-					.try_into()
-					.unwrap_or_else(|_| FedDest::default_port()),
-			));
-		}
-
-		Ok(add_port_to_hostname(delegated))
-	}
-
-	async fn resolve_3_4_use_default_port(
-		&self,
-		cache: bool,
-		delegated: String,
-	) -> Result<FedDest> {
-		debug!("3.4: No SRV records found, use the hostname from .well-known with default port");
-		self.conditional_query_and_cache(&delegated, DEFAULT_PORT, cache)
-			.await?;
-		Ok(add_port_to_hostname(&delegated))
-	}
-
-	async fn resolve_4_srv_lookup(
-		&self,
-		host: &str,
-		cache: bool,
-		overrider: FedDest,
-	) -> Result<FedDest> {
-		debug!("4: No .well-known; SRV record found");
-		let force_port = overrider.port();
-		self.conditional_query_and_cache_override(
-			host,
-			&overrider.hostname(),
-			force_port.unwrap_or(DEFAULT_PORT),
-			cache,
-		)
-		.await?;
-
-		if let Some(port) = force_port {
-			let port = format!(":{port}");
-
-			return Ok(FedDest::Named(
-				host.to_owned(),
-				PortString::from(port.as_str()).unwrap_or_else(|_| FedDest::default_port()),
-			));
-		}
-
-		Ok(add_port_to_hostname(host))
-	}
-
-	async fn resolve_5_direct(&self, dest: &ServerName, cache: bool) -> Result<FedDest> {
-		debug!("5: No port provided and no SRV record found");
-		self.conditional_query_and_cache(dest.as_str(), DEFAULT_PORT, cache)
-			.await?;
-
-		Ok(add_port_to_hostname(dest.as_str()))
-	}
-
-	#[inline]
-	async fn conditional_query_and_cache(
-		&self,
-		hostname: &str,
-		port: u16,
-		cache: bool,
-	) -> Result {
-		self.conditional_query_and_cache_override(hostname, hostname, port, cache)
-			.await
-	}
-
-	#[inline]
-	async fn conditional_query_and_cache_override(
-		&self,
-		untername: &str,
-		hostname: &str,
-		port: u16,
-		cache: bool,
-	) -> Result {
-		if !cache {
-			return Ok(());
-		}
-
-		if self.cache.has_override(untername).await {
-			return Ok(());
-		}
-
-		self.query_and_cache_override(untername, hostname, port)
-			.await
-	}
-
-	#[tracing::instrument(name = "ip", level = "debug", skip(self))]
-	async fn query_and_cache_override(
-		&self,
-		untername: &'_ str,
-		hostname: &'_ str,
-		port: u16,
-	) -> Result {
-		self.services.server.check_running()?;
-
-		debug!("querying IP for {untername:?} ({hostname:?}:{port})");
-		match self.resolver.resolver.lookup_ip(hostname.to_owned()).await {
-			| Err(e) => Self::handle_resolve_error(&e, hostname),
-			| Ok(override_ip) => {
-				self.cache.set_override(untername, &CachedOverride {
-					ips: override_ip.into_iter().take(MAX_IPS).collect(),
-					port,
-					expire: CachedOverride::default_expire(),
-					overriding: (hostname != untername)
-						.then_some(hostname.into())
-						.inspect(|_| debug_info!("{untername:?} overridden by {hostname:?}")),
-				});
-
-				Ok(())
-			},
-		}
-	}
-
-	#[tracing::instrument(name = "srv", level = "debug", skip(self))]
-	async fn query_srv_record(&self, hostname: &'_ str) -> Result<Option<FedDest>> {
-		let hostnames =
-			[format!("_matrix-fed._tcp.{hostname}."), format!("_matrix._tcp.{hostname}.")];
-
-		for hostname in hostnames {
-			self.services.server.check_running()?;
-
-			debug!("querying SRV for {hostname:?}");
-			let hostname = hostname.trim_end_matches('.');
-			match self.resolver.resolver.srv_lookup(hostname).await {
-				| Err(e) => Self::handle_resolve_error(&e, hostname)?,
-				| Ok(result) => {
-					return Ok(result.answers().iter().next().map(|result| {
-						let data = result.try_borrow::<SRV>().expect("should be SRV response");
-
-						FedDest::Named(
-							data.data()
-								.target
-								.to_string()
-								.trim_end_matches('.')
-								.to_owned(),
-							format!(":{}", data.data().port)
-								.as_str()
-								.try_into()
-								.unwrap_or_else(|_| FedDest::default_port()),
-						)
-					}));
-				},
-			}
-		}
-
-		Ok(None)
-	}
-
-	fn handle_resolve_error(err: &NetError, host: &'_ str) -> Result<()> {
-		match err {
-			| NetError::NoConnections => {
-				error!(
-					"Your DNS server is overloaded and has ran out of connections. It is \
-					 strongly recommended you remediate this issue to ensure proper federation \
-					 connectivity."
-				);
-
-				Err!(error!(%host, "DNS error: {err}"))
-			},
-			| NetError::Timeout => Err!(error!(%host, "DNS query timed out")),
-			| NetError::Dns(DnsError::NoRecordsFound(..)) => {
-				// Raise to debug_warn if we can find out the result wasn't from cache
-				debug!(%host, "No DNS records found: {err}");
-				Ok(())
-			},
-			| _ => Err!(error!(%host, "DNS error: {err}")),
-		}
-	}
-
-	/// Ensure `dest` is a valid destination (valid ip if it is an IP), and not
-	/// ourselves (unless in config)
-	fn validate_dest(&self, dest: &ServerName) -> Result<()> {
-		if dest == self.services.server.name && !self.services.server.config.federation_loopback {
-			return Err!("Won't send federation request to ourselves");
-		}
-
-		if dest.is_ip_literal() || IPAddress::is_valid(dest.host()) {
-			self.validate_dest_ip_literal(dest)?;
-		}
-
-		debug!(dest = %dest, "Valid destination for resolution");
-		Ok(())
-	}
-
-	fn validate_dest_ip_literal(&self, dest: &ServerName) -> Result<()> {
-		trace!("Destination is an IP literal, checking against IP range denylist.",);
-		debug_assert!(
-			dest.is_ip_literal() || !IPAddress::is_valid(dest.host()),
-			"Destination is not an IP literal."
-		);
-		let ip = IPAddress::parse(dest.host()).map_err(|e| {
-			err!(BadServerResponse(debug_error!("Failed to parse IP literal from string: {e}")))
-		})?;
-
-		self.validate_ip(&ip)?;
-
-		Ok(())
-	}
-
-	pub(crate) fn validate_ip(&self, ip: &IPAddress) -> Result<()> {
-		if !self.services.client.valid_cidr_range(ip) {
-			return Err!(BadServerResponse("Not allowed to send requests to this IP"));
-		}
-
-		Ok(())
-	}
-}
diff --git c/src/service/resolver/cache.rs i/src/service/resolver/cache.rs
index b0268a3cd..6ec0b5b4d 100644
--- c/src/service/resolver/cache.rs
+++ i/src/service/resolver/cache.rs
@@ -4,7 +4,7 @@
 	Result,
 	arrayvec::ArrayVec,
 	at, err,
-	utils::{math::Expected, rand, stream::TryIgnore},
+	utils::{math::Expected, stream::TryIgnore},
 };
 use database::{Cbor, Deserialized, Map};
 use futures::{Stream, StreamExt, future::join};
@@ -114,11 +114,6 @@ impl CachedDest {
 	#[must_use]
 	pub fn valid(&self) -> bool { self.expire > SystemTime::now() }

-	#[must_use]
-	pub(crate) fn default_expire() -> SystemTime {
-		rand::time_from_now_secs(60 * 60 * 18..60 * 60 * 36)
-	}
-
 	#[inline]
 	#[must_use]
 	pub fn size(&self) -> usize {
@@ -134,11 +129,6 @@ impl CachedOverride {
 	#[must_use]
 	pub fn valid(&self) -> bool { self.expire > SystemTime::now() }

-	#[must_use]
-	pub(crate) fn default_expire() -> SystemTime {
-		rand::time_from_now_secs(60 * 60 * 6..60 * 60 * 12)
-	}
-
 	#[inline]
 	#[must_use]
 	pub fn size(&self) -> usize { size_of_val(self) }
diff --git c/src/service/resolver/fed.rs i/src/service/resolver/fed.rs
index 83601a98a..f8068f596 100644
--- c/src/service/resolver/fed.rs
+++ i/src/service/resolver/fed.rs
@@ -1,8 +1,4 @@
-use std::{
-	borrow::Cow,
-	fmt,
-	net::{IpAddr, SocketAddr},
-};
+use std::{fmt, net::SocketAddr};

 use conduwuit::{arrayvec::ArrayString, utils::math::Expected};
 use serde::{Deserialize, Serialize};
@@ -18,50 +14,7 @@ pub enum FedDest {

 const DEFAULT_PORT: &str = ":8448";

-/// Attempt to parse `dest_str` as either an IP:port socket pair or as a plain
-/// IP (adding the default port), returning `None` if dest_str is neither a
-/// socket pair nor a plain IP.
-pub(crate) fn get_ip_with_port(dest_str: &str) -> Option<FedDest> {
-	if let Ok(dest) = dest_str.parse::<SocketAddr>() {
-		Some(FedDest::Literal(dest))
-	} else if let Ok(ip_addr) = dest_str.parse::<IpAddr>() {
-		Some(FedDest::Literal(SocketAddr::new(ip_addr, 8448)))
-	} else {
-		None
-	}
-}
-
-/// Convert a `dest` string with or without port into a FedDest with either
-/// the provided port (if host:port format) or the default port (8448)
-pub(crate) fn add_port_to_hostname(dest: &str) -> FedDest {
-	let (host, port) = match dest.find(':') {
-		| None => (dest, DEFAULT_PORT),
-		| Some(pos) => dest.split_at(pos),
-	};
-
-	FedDest::Named(
-		host.to_owned(),
-		PortString::from(port).unwrap_or_else(|_| FedDest::default_port()),
-	)
-}
-
-/// Ensure `host` always has a port
-///
-/// `get_ip_with_port` returns `None` if `host` isn't an IP:port string or plain
-/// IP, in which case `add_port_to_hostname` adds it instead
-#[inline]
-pub(crate) fn ensure_host_has_port(host: &str) -> FedDest {
-	get_ip_with_port(host).unwrap_or_else(|| add_port_to_hostname(host))
-}
-
 impl FedDest {
-	pub(crate) fn https_string(&self) -> String {
-		match self {
-			| Self::Literal(addr) => format!("https://{addr}"),
-			| Self::Named(host, port) => format!("https://{host}{port}"),
-		}
-	}
-
 	pub(crate) fn uri_string(&self) -> String {
 		match self {
 			| Self::Literal(addr) => addr.to_string(),
@@ -69,23 +22,6 @@ pub(crate) fn uri_string(&self) -> String {
 		}
 	}

-	#[inline]
-	pub(crate) fn hostname(&self) -> Cow<'_, str> {
-		match &self {
-			| Self::Literal(addr) => addr.ip().to_string().into(),
-			| Self::Named(host, _) => host.into(),
-		}
-	}
-
-	#[inline]
-	#[allow(clippy::string_slice)]
-	pub(crate) fn port(&self) -> Option<u16> {
-		match &self {
-			| Self::Literal(addr) => Some(addr.port()),
-			| Self::Named(_, port) => port[1..].parse().ok(),
-		}
-	}
-
 	#[inline]
 	#[must_use]
 	pub fn default_port() -> PortString {
diff --git c/src/service/resolver/mod.rs i/src/service/resolver/mod.rs
index c513cec9a..c24b8ba60 100644
--- c/src/service/resolver/mod.rs
+++ i/src/service/resolver/mod.rs
@@ -1,33 +1,31 @@
-pub mod actual;
 pub mod cache;
 mod dns;
 pub mod fed;
-#[cfg(test)]
-mod tests;
-mod well_known;

 use std::sync::Arc;

 use async_trait::async_trait;
-use conduwuit::{Result, Server, arrayvec::ArrayString, utils::MutexMap};
+use conduwuit::{Err, Result, implement};
+use ipaddress::IPAddress;
+use resolvematrix::server::MatrixResolver;

 use self::{cache::Cache, dns::Resolver};
 use crate::{Dep, client};

 pub struct Service {
-	pub cache: Arc<Cache>,
-	pub resolver: Arc<Resolver>,
-	resolving: Resolving,
+	pub resolver: MatrixResolver,
+	pub dns: Dns,
 	services: Services,
 }

 struct Services {
-	server: Arc<Server>,
 	client: Dep<client::Service>,
 }

-type Resolving = MutexMap<NameBuf, ()>;
-type NameBuf = ArrayString<256>;
+pub struct Dns {
+	pub cache: Arc<Cache>,
+	pub resolver: Arc<Resolver>,
+}

 #[async_trait]
 impl crate::Service for Service {
@@ -35,20 +33,31 @@ impl crate::Service for Service {
 	fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
 		let cache = Cache::new(&args);
 		Ok(Arc::new(Self {
-			cache: cache.clone(),
-			resolver: Resolver::build(args.server, cache)?,
-			resolving: MutexMap::new(),
+			resolver: MatrixResolver::new()?,
+			dns: Dns {
+				cache: cache.clone(),
+				resolver: Resolver::build(args.server, cache)?,
+			},
 			services: Services {
-				server: args.server.clone(),
 				client: args.depend::<client::Service>("client"),
 			},
 		}))
 	}

 	async fn clear_cache(&self) {
-		self.resolver.clear_cache();
-		self.cache.clear().await;
+		// No ability to clean resolvematrix cache at the moment
+		self.dns.resolver.clear_cache();
+		self.dns.cache.clear().await;
 	}

-	fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
+	fn name(&self) -> &str { crate::service::make_name(module_path!()) }
+}
+
+#[implement(Service)]
+pub fn validate_ip(&self, ip: &IPAddress) -> Result<()> {
+	if !self.services.client.valid_cidr_range(ip) {
+		return Err!(BadServerResponse("Not allowed to send requests to this IP"));
+	}
+
+	Ok(())
 }
diff --git c/src/service/resolver/tests.rs i/src/service/resolver/tests.rs
deleted file mode 100644
index 068e08bd0..000000000
--- c/src/service/resolver/tests.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use super::fed::{FedDest, add_port_to_hostname, get_ip_with_port};
-
-#[test]
-fn ips_get_default_ports() {
-	assert_eq!(
-		get_ip_with_port("1.1.1.1"),
-		Some(FedDest::Literal("1.1.1.1:8448".parse().unwrap()))
-	);
-	assert_eq!(
-		get_ip_with_port("dead:beef::"),
-		Some(FedDest::Literal("[dead:beef::]:8448".parse().unwrap()))
-	);
-}
-
-#[test]
-fn ips_keep_custom_ports() {
-	assert_eq!(
-		get_ip_with_port("1.1.1.1:1234"),
-		Some(FedDest::Literal("1.1.1.1:1234".parse().unwrap()))
-	);
-	assert_eq!(
-		get_ip_with_port("[dead::beef]:8933"),
-		Some(FedDest::Literal("[dead::beef]:8933".parse().unwrap()))
-	);
-}
-
-#[test]
-fn hostnames_get_default_ports() {
-	assert_eq!(
-		add_port_to_hostname("example.com"),
-		FedDest::Named(String::from("example.com"), ":8448".try_into().unwrap())
-	);
-}
-
-#[test]
-fn hostnames_keep_custom_ports() {
-	assert_eq!(
-		add_port_to_hostname("example.com:1337"),
-		FedDest::Named(String::from("example.com"), ":1337".try_into().unwrap())
-	);
-}
diff --git c/src/service/resolver/well_known.rs i/src/service/resolver/well_known.rs
deleted file mode 100644
index 2a4ecf222..000000000
--- c/src/service/resolver/well_known.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use conduwuit::{Result, debug, debug_error, debug_info, trace, utils::response::LimitReadExt};
-use ruma::ServerName;
-
-impl super::Service {
-	#[tracing::instrument(name = "well-known", level = "debug", skip(self, dest))]
-	pub(super) async fn request_well_known(&self, dest: &str) -> Result<Option<String>> {
-		trace!("Requesting well known for {dest}");
-		let response = self
-			.services
-			.client
-			.well_known
-			.get(format!("https://{dest}/.well-known/matrix/server"))
-			.send()
-			.await;
-
-		trace!("response: {response:?}");
-		if let Err(e) = &response {
-			debug!("error: {e:?}");
-			return Ok(None);
-		}
-
-		let response = response?;
-		if !response.status().is_success() {
-			debug!("response not 2XX");
-			return Ok(None);
-		}
-
-		let Ok(text) = response.limit_read_text(8192).await else {
-			debug!("failed to read well-known response (too large or non-text content)");
-			return Ok(None);
-		};
-		trace!("response text: {text:?}");
-
-		let body: serde_json::Value = serde_json::from_str(&text).unwrap_or_default();
-
-		let m_server = body
-			.get("m.server")
-			.unwrap_or(&serde_json::Value::Null)
-			.as_str()
-			.unwrap_or_default();
-
-		if ServerName::parse(m_server).is_err() {
-			debug_error!("response content missing or invalid");
-			return Ok(None);
-		}
-
-		debug_info!("{dest:?} found at {m_server:?}");
-		Ok(Some(m_server.to_owned()))
-	}
-}
2026-07-03 10:59:11 +02:00
theS1LV3R 3a90e4eaac chore: Rename variables, fix comments, misc cleanup 2026-07-03 10:59:10 +02:00
theS1LV3R a3ffd4d9c4 fix: Improve splitting of hostname:port, fixed returns 2026-07-03 10:59:10 +02:00
theS1LV3R da03baa063 fix: Ensure codeflow returns at correct locations 2026-07-03 10:59:10 +02:00
theS1LV3R f075e1ce5b chore: Remove useless comments 2026-07-03 10:59:10 +02:00
theS1LV3R 03e312f2b4 chore: Formatting + Commenting
diff --git c/src/service/resolver/actual.rs i/src/service/resolver/actual.rs
index 9cd1aec15..495d83172 100644
--- c/src/service/resolver/actual.rs
+++ i/src/service/resolver/actual.rs
@@ -1,9 +1,5 @@
 use std::fmt::Debug;

-use super::{
-	cache::{CachedDest, CachedOverride, MAX_IPS},
-	fed::{FedDest, PortString, add_port_to_hostname, ensure_host_has_port, get_ip_with_port},
-};
 use conduwuit::{Err, Result, debug, debug_info, err, error, trace};
 use futures::{FutureExt, TryFutureExt};
 use hickory_resolver::{
@@ -15,9 +11,11 @@

 use super::{
 	cache::{CachedDest, CachedOverride, MAX_IPS},
-	fed::{FedDest, PortString, add_port_to_hostname, get_ip_with_port},
+	fed::{FedDest, PortString, add_port_to_hostname, ensure_host_has_port, get_ip_with_port},
 };

+const DEFAULT_PORT: u16 = 8448;
+
 #[derive(Clone, Debug)]
 pub(crate) struct ActualDest {
 	pub(crate) dest: FedDest,
@@ -26,9 +24,7 @@ pub(crate) struct ActualDest {

 impl ActualDest {
 	#[inline]
-	pub(crate) fn string(&self) -> String {
-		self.dest.https_string()
-	}
+	pub(crate) fn string(&self) -> String { self.dest.https_string() }
 }

 impl super::Service {
@@ -75,7 +71,8 @@ pub async fn resolve_actual_dest(
 		// Ensure dest is a valid connection endpoint
 		self.validate_dest(dest)?;

-		// Clippy believes this can be a clone, however we are actually converting ServerName to String
+		// Clippy believes this can be a clone, however we are actually converting
+		// ServerName to String
 		#[allow(clippy::implicit_clone)]
 		let mut host = dest.to_string().to_owned();
 		let actual_dest = self.resolve_server_name(dest, cache, &mut host).await?;
@@ -103,8 +100,8 @@ async fn resolve_server_name(
 		cache: bool,
 		host: &mut String,
 	) -> Result<FedDest> {
-		// 1. If `dest` is an IP, use it directly. If a port is provided as well (IP:port socket pair)
-		//    use that, otherwise default to port 8448
+		// 1. If `dest` is an IP, use it directly. If a port is provided as well
+		//    (IP:port socket pair) use that, otherwise default to port 8448
 		if let Some(fed_dest) = get_ip_with_port(dest.as_str()) {
 			debug!("1: IP literal with provided or default port");
 			return Ok(fed_dest);
@@ -117,8 +114,8 @@ async fn resolve_server_name(
 				.await?;
 		}

-		// Pre-resolve IP? Unsure what overrides exactly do, system is due to be removed either way
-		// https://matrix.to/#/!da26JtAjE6APGLnX8ncWsvc-skF2KQZ9Nw_MbNpYD2k/%24_hq6JP0JXANbMTMPdV64iZbgbsZdhy92M5ndDYGy6No
+		// Pre-resolve IP? Unsure what overrides exactly do, system is due to be removed
+		// either way https://matrix.to/#/!da26JtAjE6APGLnX8ncWsvc-skF2KQZ9Nw_MbNpYD2k/%24_hq6JP0JXANbMTMPdV64iZbgbsZdhy92M5ndDYGy6No
 		self.conditional_query_and_cache(dest.as_str(), DEFAULT_PORT, true)
 			.await?;

@@ -126,7 +123,8 @@ async fn resolve_server_name(
 		self.services.server.check_running()?;

 		// 3. If `dest` is a hostname with no port, send GET to `https://<dest>/.well-known/matrix/server`.
-		// If invalid JSON (throws error), skip to step 4. Otherwise, parse `delegated` as `<hostname>[:<port>]` and...
+		// If invalid JSON (throws error), skip to step 4. Otherwise, parse `delegated`
+		// as `<hostname>[:<port>]` and...
 		if let Some(delegated) = self.request_well_known(dest.as_str()).await? {
 			// delegated=matrix-federation.matrix.org:443 // host=matrix.org
 			self.resolve_3_well_known(host, cache, delegated).await?;
@@ -137,11 +135,13 @@ async fn resolve_server_name(
 			self.resolve_4_srv_lookup(host, cache, overrider).await?;
 		}

-		// 5. if .well-known errored and no SRV exists, resolve IP and connect on default port (8448)
+		// 5. if .well-known errored and no SRV exists, resolve IP and connect on
+		//    default port (8448)
 		self.resolve_5_direct(dest, cache).await
 	}

-	/// Parse a host:port socket pair into separate parts, and resolve the hostname into an IP address
+	/// Parse a host:port socket pair into separate parts, and resolve the
+	/// hostname into an IP address
 	async fn resolve_2_host_port(
 		&self,
 		dest: &ServerName,
@@ -180,14 +180,16 @@ async fn resolve_3_well_known(
 			return Ok(host_and_port);
 		}

-		// 3.2 - If <delegated> is not an IP and a port is present, lookup IP for hostname and connect
+		// 3.2 - If <delegated> is not an IP and a port is present, lookup IP for
+		// hostname and connect
 		if let Some(pos) = &delegated.find(':') {
 			self.resolve_3_2_hostname_port(cache, &delegated, *pos)
 				.await?;
 		}

-		// 3.3 - If <delegated> is not an IP and there is no port, lookup SRV `_matrix._tcp.<delegated>`
-		// (which may provide a new hostname + port to use, see steps 3.1 and 3.2)
+		// 3.3 - If <delegated> is not an IP and there is no port, lookup SRV
+		// `_matrix._tcp.<delegated>` (which may provide a new hostname + port to use,
+		// see steps 3.1 and 3.2)
 		trace!("Delegated hostname has no port, querying SRV");
 		if let Some(overrider) = self.query_srv_record(&delegated).await? {
 			self.resolve_3_3_use_srv(cache, &delegated, overrider)
@@ -342,17 +344,14 @@ async fn query_and_cache_override(
 		match self.resolver.resolver.lookup_ip(hostname.to_owned()).await {
 			| Err(e) => Self::handle_resolve_error(&e, hostname),
 			| Ok(override_ip) => {
-				self.cache.set_override(
-					untername,
-					&CachedOverride {
-						ips: override_ip.iter().take(MAX_IPS).collect(),
-						port,
-						expire: CachedOverride::default_expire(),
-						overriding: (hostname != untername)
-							.then_some(hostname.into())
-							.inspect(|_| debug_info!("{untername:?} overridden by {hostname:?}")),
-					},
-				);
+				self.cache.set_override(untername, &CachedOverride {
+					ips: override_ip.into_iter().take(MAX_IPS).collect(),
+					port,
+					expire: CachedOverride::default_expire(),
+					overriding: (hostname != untername)
+						.then_some(hostname.into())
+						.inspect(|_| debug_info!("{untername:?} overridden by {hostname:?}")),
+				});

 				Ok(())
 			},
@@ -415,7 +414,8 @@ fn handle_resolve_error(err: &NetError, host: &'_ str) -> Result<()> {
 		}
 	}

-	/// Ensure `dest` is a valid destination (valid ip if it is an IP), and not ourselves (unless in config)
+	/// Ensure `dest` is a valid destination (valid ip if it is an IP), and not
+	/// ourselves (unless in config)
 	fn validate_dest(&self, dest: &ServerName) -> Result<()> {
 		if dest == self.services.server.name && !self.services.server.config.federation_loopback {
 			return Err!("Won't send federation request to ourselves");
diff --git c/src/service/resolver/fed.rs i/src/service/resolver/fed.rs
index b43f62eed..83601a98a 100644
--- c/src/service/resolver/fed.rs
+++ i/src/service/resolver/fed.rs
@@ -9,8 +9,8 @@

 #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub enum FedDest {
-	Literal(SocketAddr),
-	Named(String, PortString),
+	Literal(SocketAddr),       // "ip:port"
+	Named(String, PortString), // ("hostname", ":port")
 }

 /// numeric or service-name
@@ -18,6 +18,9 @@ pub enum FedDest {

 const DEFAULT_PORT: &str = ":8448";

+/// Attempt to parse `dest_str` as either an IP:port socket pair or as a plain
+/// IP (adding the default port), returning `None` if dest_str is neither a
+/// socket pair nor a plain IP.
 pub(crate) fn get_ip_with_port(dest_str: &str) -> Option<FedDest> {
 	if let Ok(dest) = dest_str.parse::<SocketAddr>() {
 		Some(FedDest::Literal(dest))
@@ -28,6 +31,8 @@ pub(crate) fn get_ip_with_port(dest_str: &str) -> Option<FedDest> {
 	}
 }

+/// Convert a `dest` string with or without port into a FedDest with either
+/// the provided port (if host:port format) or the default port (8448)
 pub(crate) fn add_port_to_hostname(dest: &str) -> FedDest {
 	let (host, port) = match dest.find(':') {
 		| None => (dest, DEFAULT_PORT),
@@ -42,8 +47,8 @@ pub(crate) fn add_port_to_hostname(dest: &str) -> FedDest {

 /// Ensure `host` always has a port
 ///
-/// `get_ip_with_port` returns `None` if `host` isn't an IP:port string or plain IP,
-/// in which case `add_port_to_hostname` adds it instead
+/// `get_ip_with_port` returns `None` if `host` isn't an IP:port string or plain
+/// IP, in which case `add_port_to_hostname` adds it instead
 #[inline]
 pub(crate) fn ensure_host_has_port(host: &str) -> FedDest {
 	get_ip_with_port(host).unwrap_or_else(|| add_port_to_hostname(host))
2026-07-03 10:59:10 +02:00
theS1LV3R cb031aef84 refactor: Rewrite resolver service
No functional changes, only visual and slight logic updates.
All inputs should return the same outputs.

# Conflicts:
#	src/service/resolver/actual.rs

diff --git c/src/service/resolver/actual.rs i/src/service/resolver/actual.rs
index 7eaeb96ab..9cd1aec15 100644
--- c/src/service/resolver/actual.rs
+++ i/src/service/resolver/actual.rs
@@ -1,8 +1,9 @@
-use std::{
-	fmt::Debug,
-	net::{IpAddr, SocketAddr},
-};
+use std::fmt::Debug;

+use super::{
+	cache::{CachedDest, CachedOverride, MAX_IPS},
+	fed::{FedDest, PortString, add_port_to_hostname, ensure_host_has_port, get_ip_with_port},
+};
 use conduwuit::{Err, Result, debug, debug_info, err, error, trace};
 use futures::{FutureExt, TryFutureExt};
 use hickory_resolver::{
@@ -25,7 +26,9 @@ pub(crate) struct ActualDest {

 impl ActualDest {
 	#[inline]
-	pub(crate) fn string(&self) -> String { self.dest.https_string() }
+	pub(crate) fn string(&self) -> String {
+		self.dest.https_string()
+	}
 }

 impl super::Service {
@@ -57,71 +60,103 @@ pub(crate) async fn lookup_actual_dest(
 			.await
 	}

-	/// Returns: `actual_destination`, host header
-	/// Implemented according to the specification at <https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names>
-	/// Numbers in comments below refer to bullet points in linked section of
-	/// specification
+	/// Returns: `actual_destination` + `host` variable used for logging
 	#[tracing::instrument(name = "actual", level = "debug", skip(self, cache))]
 	pub async fn resolve_actual_dest(
 		&self,
 		dest: &ServerName,
 		cache: bool,
 	) -> Result<CachedDest> {
+		debug!(
+			dest = %dest,
+			cache = %cache,
+			"Resolving server name and port"
+		);
+		// Ensure dest is a valid connection endpoint
 		self.validate_dest(dest)?;
-		let mut host = dest.as_str().to_owned();
-		let actual_dest = match get_ip_with_port(dest.as_str()) {
-			| Some(host_port) => Self::actual_dest_1(host_port)?,
-			| None =>
-				if let Some(pos) = dest.as_str().find(':') {
-					self.actual_dest_2(dest, cache, pos).await?
-				} else {
-					self.services.server.check_running()?;
-					match self.request_well_known(dest.as_str()).await? {
-						| Some(delegated) =>
-							self.actual_dest_3(&mut host, cache, delegated).await?,
-						| _ => match self.query_srv_record(dest.as_str()).await? {
-							| Some(overrider) =>
-								self.actual_dest_4(&host, cache, overrider).await?,
-							| _ => self.actual_dest_5(dest, cache).await?,
-						},
-					}
-				},
-		};

-		// Can't use get_ip_with_port here because we don't want to add a port
-		// to an IP address if it wasn't specified
-		let host = if let Ok(addr) = host.parse::<SocketAddr>() {
-			FedDest::Literal(addr)
-		} else if let Ok(addr) = host.parse::<IpAddr>() {
-			FedDest::Named(addr.to_string(), FedDest::default_port())
-		} else if let Some(pos) = host.find(':') {
-			let (host, port) = host.split_at(pos);
-			FedDest::Named(
-				host.to_owned(),
-				port.try_into().unwrap_or_else(|_| FedDest::default_port()),
-			)
-		} else {
-			FedDest::Named(host, FedDest::default_port())
-		};
+		// Clippy believes this can be a clone, however we are actually converting ServerName to String
+		#[allow(clippy::implicit_clone)]
+		let mut host = dest.to_string().to_owned();
+		let actual_dest = self.resolve_server_name(dest, cache, &mut host).await?;

-		debug!("Actual destination: {actual_dest:?} hostname: {host:?}");
+		host = ensure_host_has_port(&host).to_string();
+
+		debug!(
+			dest = %dest, // matrix.org
+			actual_dest = %actual_dest, // FedDest::Named(server.matrix.org, 443)
+			host = %host, // matrix.org
+			"Finished resolving server name"
+		);
 		Ok(CachedDest {
 			dest: actual_dest,
-			host: host.uri_string(),
+			host,
 			expire: CachedDest::default_expire(),
 		})
 	}

-	fn actual_dest_1(host_port: FedDest) -> Result<FedDest> {
-		debug!("1: IP literal with provided or default port");
-		Ok(host_port)
+	/// Performs the server resolution steps as per the specification:
+	/// <https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names>
+	async fn resolve_server_name(
+		&self,
+		dest: &ServerName,
+		cache: bool,
+		host: &mut String,
+	) -> Result<FedDest> {
+		// 1. If `dest` is an IP, use it directly. If a port is provided as well (IP:port socket pair)
+		//    use that, otherwise default to port 8448
+		if let Some(fed_dest) = get_ip_with_port(dest.as_str()) {
+			debug!("1: IP literal with provided or default port");
+			return Ok(fed_dest);
+		}
+
+		// 2. If `dest` is a hostname and has a provided port (format of `host:port`),
+		//    resolve the hostname to an IP address and connect it and the provided port
+		if let Some(colon_position) = dest.as_str().find(':') {
+			self.resolve_2_host_port(dest, cache, colon_position)
+				.await?;
+		}
+
+		// Pre-resolve IP? Unsure what overrides exactly do, system is due to be removed either way
+		// https://matrix.to/#/!da26JtAjE6APGLnX8ncWsvc-skF2KQZ9Nw_MbNpYD2k/%24_hq6JP0JXANbMTMPdV64iZbgbsZdhy92M5ndDYGy6No
+		self.conditional_query_and_cache(dest.as_str(), DEFAULT_PORT, true)
+			.await?;
+
+		// Ensure server is running (not shutting down) before continuing resolution
+		self.services.server.check_running()?;
+
+		// 3. If `dest` is a hostname with no port, send GET to `https://<dest>/.well-known/matrix/server`.
+		// If invalid JSON (throws error), skip to step 4. Otherwise, parse `delegated` as `<hostname>[:<port>]` and...
+		if let Some(delegated) = self.request_well_known(dest.as_str()).await? {
+			// delegated=matrix-federation.matrix.org:443 // host=matrix.org
+			self.resolve_3_well_known(host, cache, delegated).await?;
+		}
+
+		// 4. if .well-known errored, perform SRV (see 3.3)
+		if let Some(overrider) = self.query_srv_record(dest.as_str()).await? {
+			self.resolve_4_srv_lookup(host, cache, overrider).await?;
+		}
+
+		// 5. if .well-known errored and no SRV exists, resolve IP and connect on default port (8448)
+		self.resolve_5_direct(dest, cache).await
 	}

-	async fn actual_dest_2(&self, dest: &ServerName, cache: bool, pos: usize) -> Result<FedDest> {
+	/// Parse a host:port socket pair into separate parts, and resolve the hostname into an IP address
+	async fn resolve_2_host_port(
+		&self,
+		dest: &ServerName,
+		cache: bool,
+		pos: usize,
+	) -> Result<FedDest> {
 		debug!("2: Hostname with included port");
 		let (host, port) = dest.as_str().split_at(pos);
-		self.conditional_query_and_cache(host, port.parse::<u16>().unwrap_or(8448), cache)
-			.await?;
+
+		self.conditional_query_and_cache(
+			host,
+			port.parse::<u16>().unwrap_or(DEFAULT_PORT),
+			cache,
+		)
+		.await?;

 		Ok(FedDest::Named(
 			host.to_owned(),
@@ -129,7 +164,7 @@ async fn actual_dest_2(&self, dest: &ServerName, cache: bool, pos: usize) -> Res
 		))
 	}

-	async fn actual_dest_3(
+	async fn resolve_3_well_known(
 		&self,
 		host: &mut String,
 		cache: bool,
@@ -137,63 +172,75 @@ async fn actual_dest_3(
 	) -> Result<FedDest> {
 		debug!("3: A .well-known file is available");
 		*host = add_port_to_hostname(&delegated).uri_string();
-		match get_ip_with_port(&delegated) {
-			| Some(host_and_port) => Self::actual_dest_3_1(host_and_port),
-			| None =>
-				if let Some(pos) = delegated.find(':') {
-					self.actual_dest_3_2(cache, delegated, pos).await
-				} else {
-					trace!("Delegated hostname has no port in this branch");
-					match self.query_srv_record(&delegated).await? {
-						| Some(overrider) =>
-							self.actual_dest_3_3(cache, delegated, overrider).await,
-						| _ => self.actual_dest_3_4(cache, delegated).await,
-					}
-				},
+
+		// 3.1 - If <delegated> is of IP:port format, connect to that,
+		//       or IP with default port if no port provided (8448)
+		if let Some(host_and_port) = get_ip_with_port(&delegated) {
+			debug!("3.1: IP with port in .well-known file");
+			return Ok(host_and_port);
 		}
+
+		// 3.2 - If <delegated> is not an IP and a port is present, lookup IP for hostname and connect
+		if let Some(pos) = &delegated.find(':') {
+			self.resolve_3_2_hostname_port(cache, &delegated, *pos)
+				.await?;
+		}
+
+		// 3.3 - If <delegated> is not an IP and there is no port, lookup SRV `_matrix._tcp.<delegated>`
+		// (which may provide a new hostname + port to use, see steps 3.1 and 3.2)
+		trace!("Delegated hostname has no port, querying SRV");
+		if let Some(overrider) = self.query_srv_record(&delegated).await? {
+			self.resolve_3_3_use_srv(cache, &delegated, overrider)
+				.await?;
+		}
+
+		self.resolve_3_4_use_default_port(cache, delegated).await
 	}

-	fn actual_dest_3_1(host_and_port: FedDest) -> Result<FedDest> {
-		debug!("3.1: IP literal in .well-known file");
-		Ok(host_and_port)
-	}
-
-	async fn actual_dest_3_2(
+	async fn resolve_3_2_hostname_port(
 		&self,
 		cache: bool,
-		delegated: String,
+		delegated: &str,
 		pos: usize,
 	) -> Result<FedDest> {
 		debug!("3.2: Hostname with port in .well-known file");
-		let (host, port) = delegated.split_at(pos);
-		self.conditional_query_and_cache(host, port.parse::<u16>().unwrap_or(8448), cache)
-			.await?;
+		let (host, port) = &delegated.split_at(pos);
+		self.conditional_query_and_cache(
+			host,
+			port.parse::<u16>().unwrap_or(DEFAULT_PORT),
+			cache,
+		)
+		.await?;

+		trace!("Successfully resolved IP for {delegated}");
 		Ok(FedDest::Named(
-			host.to_owned(),
-			port.try_into().unwrap_or_else(|_| FedDest::default_port()),
+			host.to_owned().to_owned(),
+			port.to_owned()
+				.try_into()
+				.unwrap_or_else(|_| FedDest::default_port()),
 		))
 	}

-	async fn actual_dest_3_3(
+	async fn resolve_3_3_use_srv(
 		&self,
 		cache: bool,
-		delegated: String,
+		delegated: &String,
 		overrider: FedDest,
 	) -> Result<FedDest> {
 		debug!("3.3: SRV lookup successful");
+
 		let force_port = overrider.port();
 		self.conditional_query_and_cache_override(
-			&delegated,
+			delegated,
 			&overrider.hostname(),
-			force_port.unwrap_or(8448),
+			force_port.unwrap_or(DEFAULT_PORT),
 			cache,
 		)
 		.await?;

 		if let Some(port) = force_port {
 			return Ok(FedDest::Named(
-				delegated,
+				delegated.to_owned(),
 				format!(":{port}")
 					.as_str()
 					.try_into()
@@ -201,17 +248,21 @@ async fn actual_dest_3_3(
 			));
 		}

-		Ok(add_port_to_hostname(&delegated))
+		Ok(add_port_to_hostname(delegated))
 	}

-	async fn actual_dest_3_4(&self, cache: bool, delegated: String) -> Result<FedDest> {
-		debug!("3.4: No SRV records, just use the hostname from .well-known");
-		self.conditional_query_and_cache(&delegated, 8448, cache)
+	async fn resolve_3_4_use_default_port(
+		&self,
+		cache: bool,
+		delegated: String,
+	) -> Result<FedDest> {
+		debug!("3.4: No SRV records found, use the hostname from .well-known with default port");
+		self.conditional_query_and_cache(&delegated, DEFAULT_PORT, cache)
 			.await?;
 		Ok(add_port_to_hostname(&delegated))
 	}

-	async fn actual_dest_4(
+	async fn resolve_4_srv_lookup(
 		&self,
 		host: &str,
 		cache: bool,
@@ -222,7 +273,7 @@ async fn actual_dest_4(
 		self.conditional_query_and_cache_override(
 			host,
 			&overrider.hostname(),
-			force_port.unwrap_or(8448),
+			force_port.unwrap_or(DEFAULT_PORT),
 			cache,
 		)
 		.await?;
@@ -239,9 +290,9 @@ async fn actual_dest_4(
 		Ok(add_port_to_hostname(host))
 	}

-	async fn actual_dest_5(&self, dest: &ServerName, cache: bool) -> Result<FedDest> {
-		debug!("5: No SRV record found");
-		self.conditional_query_and_cache(dest.as_str(), 8448, cache)
+	async fn resolve_5_direct(&self, dest: &ServerName, cache: bool) -> Result<FedDest> {
+		debug!("5: No port provided and no SRV record found");
+		self.conditional_query_and_cache(dest.as_str(), DEFAULT_PORT, cache)
 			.await?;

 		Ok(add_port_to_hostname(dest.as_str()))
@@ -261,9 +312,9 @@ async fn conditional_query_and_cache(
 	#[inline]
 	async fn conditional_query_and_cache_override(
 		&self,
-		untername: &str,
-		hostname: &str,
-		port: u16,
+		untername: &str, // matrix.org
+		hostname: &str,  // server.matrix.org
+		port: u16,       // 443
 		cache: bool,
 	) -> Result {
 		if !cache {
@@ -281,9 +332,9 @@ async fn conditional_query_and_cache_override(
 	#[tracing::instrument(name = "ip", level = "debug", skip(self))]
 	async fn query_and_cache_override(
 		&self,
-		untername: &'_ str,
-		hostname: &'_ str,
-		port: u16,
+		untername: &'_ str, // matrix.org
+		hostname: &'_ str,  // server.matrix.org
+		port: u16,          // 443
 	) -> Result {
 		self.services.server.check_running()?;

@@ -291,14 +342,17 @@ async fn query_and_cache_override(
 		match self.resolver.resolver.lookup_ip(hostname.to_owned()).await {
 			| Err(e) => Self::handle_resolve_error(&e, hostname),
 			| Ok(override_ip) => {
-				self.cache.set_override(untername, &CachedOverride {
-					ips: override_ip.iter().take(MAX_IPS).collect(),
-					port,
-					expire: CachedOverride::default_expire(),
-					overriding: (hostname != untername)
-						.then_some(hostname.into())
-						.inspect(|_| debug_info!("{untername:?} overridden by {hostname:?}")),
-				});
+				self.cache.set_override(
+					untername,
+					&CachedOverride {
+						ips: override_ip.iter().take(MAX_IPS).collect(),
+						port,
+						expire: CachedOverride::default_expire(),
+						overriding: (hostname != untername)
+							.then_some(hostname.into())
+							.inspect(|_| debug_info!("{untername:?} overridden by {hostname:?}")),
+					},
+				);

 				Ok(())
 			},
@@ -361,6 +415,7 @@ fn handle_resolve_error(err: &NetError, host: &'_ str) -> Result<()> {
 		}
 	}

+	/// Ensure `dest` is a valid destination (valid ip if it is an IP), and not ourselves (unless in config)
 	fn validate_dest(&self, dest: &ServerName) -> Result<()> {
 		if dest == self.services.server.name && !self.services.server.config.federation_loopback {
 			return Err!("Won't send federation request to ourselves");
@@ -370,6 +425,7 @@ fn validate_dest(&self, dest: &ServerName) -> Result<()> {
 			self.validate_dest_ip_literal(dest)?;
 		}

+		debug!(dest = %dest, "Valid destination for resolution");
 		Ok(())
 	}

diff --git c/src/service/resolver/fed.rs i/src/service/resolver/fed.rs
index e5bee9ac2..b43f62eed 100644
--- c/src/service/resolver/fed.rs
+++ i/src/service/resolver/fed.rs
@@ -40,6 +40,15 @@ pub(crate) fn add_port_to_hostname(dest: &str) -> FedDest {
 	)
 }

+/// Ensure `host` always has a port
+///
+/// `get_ip_with_port` returns `None` if `host` isn't an IP:port string or plain IP,
+/// in which case `add_port_to_hostname` adds it instead
+#[inline]
+pub(crate) fn ensure_host_has_port(host: &str) -> FedDest {
+	get_ip_with_port(host).unwrap_or_else(|| add_port_to_hostname(host))
+}
+
 impl FedDest {
 	pub(crate) fn https_string(&self) -> String {
 		match self {
2026-07-03 10:59:06 +02:00
timedout 0c9230f35e style: Document & refactor resolver service
good riddance to this thing
2026-06-27 18:36:44 +01:00
Ginger 0932c929c3 chore: Clippy fixes >:( 2026-06-16 12:36:24 -04:00
Ginger 8f4e95b4b9 fix: Fix compile errors caused by hickory upgrade 2026-06-16 12:19:37 -04:00
Ginger e70004c98f chore: Clippy fixes 2026-04-28 09:16:56 -04:00
Ginger 24f7e1d658 chore: Clippy fixes 2026-04-28 09:16:51 -04:00
GingerandJade Ellis 204bc1367e refactor: Ruma upstreaming, half-baked edition
Co-authored-by: Jade Ellis <jade@ellis.link>
2026-04-28 09:16:51 -04:00
Tulir Asokan 8b762cf2e6 fix: Server name caching for SRV remotes 2026-04-06 19:57:05 +00:00
timedout f0c3fdfe3a fix: Well-known read errors no longer crash resolver flow
Reviewed-By: Jade Ellis <jade@ellis.link>
2026-03-27 00:54:17 +00:00
timedout 37888fb670 fix: Limit body read size of remote requests (CWE-409)
Reviewed-By: Jade Ellis <jade@ellis.link>
2026-03-03 19:54:34 +00:00
Jade Ellis 01594a6243 chore: Fix typos across the codebase 2025-05-06 20:51:12 +01:00
Jason Volk 58adb6fead upgrade hickory and hyper-util dependencies
Signed-off-by: Jason Volk <jason@zemos.net>
2025-04-03 19:38:51 +00:00
Jason Volk 23e3f6526f split well_known resolver into unit
Signed-off-by: Jason Volk <jason@zemos.net>
2025-03-26 01:33:41 +00:00
Jason Volk 8010505853 implement clear_cache() for resolver service
Signed-off-by: Jason Volk <jason@zemos.net>
2025-03-26 01:33:41 +00:00
June Clementine Strawberry af714d5778 refactor+fix various issues with regs/logins and admin user commands
Signed-off-by: June Clementine Strawberry <june@3.dog>
2025-03-02 23:16:30 -05:00
June Clementine Strawberry a1e1f40ded run cargo fix for rust 2024 changes and rustfmt
Signed-off-by: June Clementine Strawberry <strawberry@puppygock.gay>
2025-02-23 01:17:45 -05:00
Jason Volk b872f8e593 optimize with SmallString; consolidate related re-exports
Signed-off-by: Jason Volk <jason@zemos.net>
2025-02-16 17:40:21 -05:00
Jason Volk 3e0ff2dc84 simplify references to server_name
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-28 18:36:00 +00:00
Jason Volk 184a3b0f0c reduce some tracing span levels; bump ruma
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-25 01:35:18 +00:00
Jason Volk a5520e8b1b fix SRV override loss on cache expiration
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-23 01:48:53 +00:00
Jason Volk da9f1ae5d7 expire resolver cache entries
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 08:51:56 +00:00
Jason Volk 607e338ac2 cache result of resolution at completion of resolution
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 07:56:24 +00:00
Jason Volk f75d9fa79e deduplicate name resolutions
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 06:57:18 +00:00
Jason Volk 49023aa295 use database for resolver caches
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-22 02:16:51 +00:00
Jason Volk b8f8f68634 improve memory-usage output w/ more byte-sizes
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk 9c6b5b4407 add faster interruption to resolver (#649)
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk a407909d09 reduce unnecessary info-level spans to debug
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk e5a1309583 additional interruption points to hasten shutdown
Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
Jason Volk af3d6a2e37 shard sender into multiple task workers by destination hash
rename Destination::Normal variant

tracing instruments

Signed-off-by: Jason Volk <jason@zemos.net>
2025-01-01 23:28:01 -05:00
strawberry c8c9d73b20 enable edns0 on hickory resolver config
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 17:24:45 -05:00
strawberry 77e0b76408 apply new rustfmt.toml changes, fix some clippy lints
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-15 01:00:41 -05:00
strawberry 0317cc8cc5 rename conduit to conduwuit finally
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-14 22:24:45 -05:00
strawberry 66a82447da log hostname in DNS error tracing spans
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-12-11 21:24:53 -05:00
Jason Volk aba88ccead misc tracing span tweaks
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-10 06:20:30 +00:00
Jason Volk c01b049910 move cidr_range_denylist from globals to client service
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-04 00:51:57 +00:00
Jason Volk ed8c21ac9a modernize async srv lookup
Signed-off-by: Jason Volk <jason@zemos.net>
2024-12-03 13:25:33 +00:00
strawberry f15370027e improve DNS error messages
Signed-off-by: strawberry <strawberry@puppygock.gay>
2024-11-23 12:05:52 -05:00
Jason Volk 1f1e2d547c optimize override ips; utilize all ips from cache
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 08:03:25 +00:00
Jason Volk 1fbfc983e9 optimize FedDest::Named port
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-03 07:32:09 +00:00
Jason Volk 52e356d780 generate ActualDest https string on the fly
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-28 20:52:52 -04:00
Jason Volk e7e606300f slightly simplify reqwest/hickory hooks
Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-27 19:17:41 +00:00
Jason Volk 946ca364e0 Database Refactor
combine service/users data w/ mod unit

split sliding sync related out of service/users

instrument database entry points

remove increment crap from database interface

de-wrap all database get() calls

de-wrap all database insert() calls

de-wrap all database remove() calls

refactor database interface for async streaming

add query key serializer for database

implement Debug for result handle

add query deserializer for database

add deserialization trait for option handle

start a stream utils suite

de-wrap/asyncify/type-query count_one_time_keys()

de-wrap/asyncify users count

add admin query users command suite

de-wrap/asyncify users exists

de-wrap/partially asyncify user filter related

asyncify/de-wrap users device/keys related

asyncify/de-wrap user auth/misc related

asyncify/de-wrap users blurhash

asyncify/de-wrap account_data get; merge Data into Service

partial asyncify/de-wrap uiaa; merge Data into Service

partially asyncify/de-wrap transaction_ids get; merge Data into Service

partially asyncify/de-wrap key_backups; merge Data into Service

asyncify/de-wrap pusher service getters; merge Data into Service

asyncify/de-wrap rooms alias getters/some iterators

asyncify/de-wrap rooms directory getters/iterator

partially asyncify/de-wrap rooms lazy-loading

partially asyncify/de-wrap rooms metadata

asyncify/dewrap rooms outlier

asyncify/dewrap rooms pdu_metadata

dewrap/partially asyncify rooms read receipt

de-wrap rooms search service

de-wrap/partially asyncify rooms user service

partial de-wrap rooms state_compressor

de-wrap rooms state_cache

de-wrap room state et al

de-wrap rooms timeline service

additional users device/keys related

de-wrap/asyncify sender

asyncify services

refactor database to TryFuture/TryStream

refactor services for TryFuture/TryStream

asyncify api handlers

additional asyncification for admin module

abstract stream related; support reverse streams

additional stream conversions

asyncify state-res related

Signed-off-by: Jason Volk <jason@zemos.net>
2024-10-25 00:32:30 -04:00