From 63555db48a8a276ac40d5e201993c602515ee2b8 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 29 Apr 2026 18:20:21 +0000 Subject: [PATCH] fix(nests): use moq-auth.nostrnests.com for JWT mint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous defaults pointed both `service` and `endpoint` URLs at `moq.nostrnests.com:4443`. That host only listens on UDP/QUIC for the WebTransport relay — TCP :4443 is unreachable. OkHttp can't speak HTTP/3, so the JWT-mint POST hangs and fails with `ConnectException`, leaving the room screen stuck on "Reconnecting". The real nostrnests deployment co-locates auth and relay on different hosts (verified against the production NestsUI bundle): relay (WebTransport, QUIC only): https://moq.nostrnests.com:4443 auth (JWT mint, regular HTTPS): https://moq-auth.nostrnests.com Split the defaults accordingly and add a `resolveServerPair` helper that maps a single saved kind-10112 URL onto the (service, endpoint) pair the kind-30312 event needs. The helper recognises both the auth-host and the legacy relay-host the prior defaults wrote, so users upgrading from the broken version migrate transparently the next time they open the create-room sheet. Community deployments that genuinely co-locate keep working via the fallback. Update the recommended-servers list and the kind-10112 documentation to match: the stored `server` URL is the moq-auth base (the URL that ends up in the kind-30312 `service` tag). --- .../nestsServers/NestsServersScreen.kt | 7 +++- .../nestsServers/NestsServersViewModel.kt | 11 ++++-- .../nests/create/CreateNestViewModel.kt | 35 +++++++++++++++++-- .../nestsServers/NestsServersEvent.kt | 18 ++++++---- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersScreen.kt index 669f83a19..2ec17fef1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersScreen.kt @@ -247,8 +247,13 @@ private fun NestsServerEntry( * Built-in suggestion list shown under "Recommended servers". Today * just the public `nostrnests.com` deployment; add new entries here * as community-run moq-rs / moq-auth instances come online. + * + * The stored URL is the moq-auth (service / JWT mint) base — that's + * the URL that ends up in the kind-30312 `service` tag. The matching + * WebTransport relay endpoint is resolved by + * [com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.create.CreateNestViewModel.resolveServerPair]. */ val DEFAULT_NESTS_SERVERS: List = listOf( - NestsServer(name = "nostrnests.com", baseUrl = "https://moq.nostrnests.com:4443"), + NestsServer(name = "nostrnests.com", baseUrl = "https://moq-auth.nostrnests.com"), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersViewModel.kt index 52f0d5ad8..b4b37935f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersViewModel.kt @@ -115,7 +115,11 @@ class NestsServersViewModel : ViewModel() { private fun displayHostName(url: String): String = try { - Rfc3986.host(url).removePrefix("moq.").removePrefix("nests.") + Rfc3986 + .host(url) + .removePrefix("moq-auth.") + .removePrefix("moq.") + .removePrefix("nests.") } catch (_: Throwable) { url } @@ -124,7 +128,10 @@ class NestsServersViewModel : ViewModel() { /** * Display-friendly entry for [NestsServersViewModel]. * - [name] — short host label (e.g. `nostrnests.com`) - * - [baseUrl] — exact bytes that go on the wire (`https://moq.nostrnests.com`) + * - [baseUrl] — exact bytes that go on the wire as the kind-30312 + * `service` tag (`https://moq-auth.nostrnests.com`). The matching + * WebTransport endpoint is resolved at room-create time, not + * stored here. */ data class NestsServer( val name: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestViewModel.kt index c4c57e46d..647611622 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestViewModel.kt @@ -79,7 +79,8 @@ class CreateNestViewModel : ViewModel() { .firstOrNull() ?.takeIf { it.startsWith("http") } if (savedFirst != null) { - _state.update { it.copy(serviceUrl = savedFirst, endpointUrl = savedFirst) } + val (service, endpoint) = resolveServerPair(savedFirst) + _state.update { it.copy(serviceUrl = service, endpointUrl = endpoint) } } } @@ -355,8 +356,38 @@ class CreateNestViewModel : ViewModel() { * Public nostrnests deployment — a blank form produces a working * room here. Users can edit either field to point at their own * moq-auth / moq-relay pair. + * + * The auth sidecar (moq-auth) and the WebTransport relay + * (moq-rs) are on different hosts: moq-auth speaks regular + * HTTPS on :443 to mint JWTs; moq.nostrnests.com:4443 is the + * QUIC/WebTransport endpoint and does NOT accept TCP. Don't + * collapse them back into a single URL — OkHttp can't speak + * HTTP/3, so a TCP POST to :4443 will hang and fail. */ - const val DEFAULT_SERVICE_URL: String = "https://moq.nostrnests.com:4443" + const val DEFAULT_SERVICE_URL: String = "https://moq-auth.nostrnests.com" const val DEFAULT_ENDPOINT_URL: String = "https://moq.nostrnests.com:4443" + + /** + * Map a single saved kind-10112 URL onto the (service, endpoint) + * pair the kind-30312 event needs. Recognises the public + * nostrnests deployment (whether the user has the auth host or + * the relay host saved — earlier app versions stored the relay + * URL by mistake), and falls back to using the URL for both + * tags so community-run deployments that genuinely co-locate + * keep working. + */ + internal fun resolveServerPair(savedUrl: String): Pair = + when (savedUrl.trimEnd('/')) { + "https://moq-auth.nostrnests.com", + "https://moq.nostrnests.com:4443", + "https://moq.nostrnests.com", + -> { + DEFAULT_SERVICE_URL to DEFAULT_ENDPOINT_URL + } + + else -> { + savedUrl to savedUrl + } + } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/nestsServers/NestsServersEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/nestsServers/NestsServersEvent.kt index b38277b18..d62bbccef 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/nestsServers/NestsServersEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/nestsServers/NestsServersEvent.kt @@ -42,19 +42,23 @@ import com.vitorpamplona.quartz.utils.TimeUtils * "kind": 10112, * "tags": [ * ["alt", "Audio-room (nests) MoQ servers used by the author"], - * ["server", "https://moq.nostrnests.com"], + * ["server", "https://moq-auth.nostrnests.com"], * ["server", "https://moq.example.org"], * ... * ], * "content": "" * } * - * The `server` URL points at the moq-rs / moq-auth deployment's base - * URL — Amethyst's `CreateNestSheet` uses it for both the - * `service` (auth sidecar) and `endpoint` (WebTransport relay) tags - * on the kind-30312 event, since nostrnests's reference deployment - * co-locates them. A future revision can split the two into separate - * tag fields if the community pulls them apart. + * The `server` URL is the moq-auth (JWT mint) base — that's also the + * URL that goes into the kind-30312 `service` tag. The matching + * WebTransport relay endpoint is NOT part of this list; reference + * deployments like nostrnests run the auth sidecar on regular HTTPS + * (e.g. `https://moq-auth.nostrnests.com`) and the QUIC relay on a + * separate host/port (e.g. `https://moq.nostrnests.com:4443`), so + * Amethyst's `CreateNestSheet` resolves the pair via a known-deployment + * mapping (with a fallback that reuses the saved URL for both tags + * when a community deployment genuinely co-locates them). A future + * revision can split the two into separate tag fields if needed. * * This event is shaped 1:1 after `BlossomServersEvent` (kind 10063, * NIP-B7) so existing list-state / settings UI patterns translate