From 9a0ad0c6630f95670303da9f6d6e31c86c308c13 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Thu, 8 Jan 2026 16:01:36 -0800 Subject: [PATCH] Improve space join flow --- package.json | 5 ++- src/app/components/SpaceCheck.svelte | 12 ++++--- src/app/components/SpaceEdit.svelte | 2 +- src/app/components/SpaceInvite.svelte | 3 +- src/app/core/commands.ts | 44 ++++++++++++++++++++---- src/app/core/state.ts | 40 +-------------------- src/routes/spaces/[relay]/+layout.svelte | 3 +- 7 files changed, 54 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index 9c14f4b7..4e207d1f 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "qrcode": "^1.5.4", "throttle-debounce": "^5.0.2", "tippy.js": "^6.3.7", - "@pomade/core": "^0.0.5" + "@pomade/core": "^0.0.7" }, "pnpm": { "ignoredBuiltDependencies": [ @@ -106,8 +106,7 @@ "@welshman/router": "link:../welshman/packages/router", "@welshman/signer": "link:../welshman/packages/signer", "@welshman/store": "link:../welshman/packages/store", - "@welshman/util": "link:../welshman/packages/util", - "@pomade/core": "link:../pomade/packages/core" + "@welshman/util": "link:../welshman/packages/util" } } } diff --git a/src/app/components/SpaceCheck.svelte b/src/app/components/SpaceCheck.svelte index bd38759e..fc5ca2b5 100644 --- a/src/app/components/SpaceCheck.svelte +++ b/src/app/components/SpaceCheck.svelte @@ -10,10 +10,10 @@ import Button from "@lib/components/Button.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" + import SpaceAccessRequest from "@app/components/SpaceAccessRequest.svelte" import SpaceJoinConfirm, {confirmSpaceJoin} from "@app/components/SpaceJoinConfirm.svelte" import {attemptRelayAccess} from "@app/core/commands" import {pushModal} from "@app/util/modal" - import {pushToast} from "@app/util/toast" const {url} = $props() @@ -21,7 +21,7 @@ const next = async () => { if (error) { - return pushToast({theme: "error", message: error, timeout: 30_000}) + return pushModal(SpaceAccessRequest, {url}) } if (Pool.get().get(url).auth.status === AuthStatus.None) { @@ -35,7 +35,7 @@ let loading = $state(true) onMount(async () => { - ;[error] = await Promise.all([attemptRelayAccess(url), sleep(3000)]) + ;[error] = await Promise.all([attemptRelayAccess(url), sleep(1000)]) loading = false }) @@ -77,7 +77,11 @@ Go back diff --git a/src/app/components/SpaceEdit.svelte b/src/app/components/SpaceEdit.svelte index 1ec358ef..83762f04 100644 --- a/src/app/components/SpaceEdit.svelte +++ b/src/app/components/SpaceEdit.svelte @@ -21,7 +21,7 @@ type Props = { url: string - initialValues: RelayProfile + initialValues: Partial } const {url, initialValues = {}}: Props = $props() diff --git a/src/app/components/SpaceInvite.svelte b/src/app/components/SpaceInvite.svelte index ceb11445..f44de9e7 100644 --- a/src/app/components/SpaceInvite.svelte +++ b/src/app/components/SpaceInvite.svelte @@ -13,7 +13,8 @@ import ModalFooter from "@lib/components/ModalFooter.svelte" import QRCode from "@app/components/QRCode.svelte" import {clip} from "@app/util/toast" - import {PLATFORM_URL, deriveRelayAuthError} from "@app/core/state" + import {PLATFORM_URL} from "@app/core/state" + import {deriveRelayAuthError} from "@app/core/commands" const {url} = $props() diff --git a/src/app/core/commands.ts b/src/app/core/commands.ts index 18b21bc1..f2b04d51 100644 --- a/src/app/core/commands.ts +++ b/src/app/core/commands.ts @@ -1,6 +1,6 @@ import {nwc} from "@getalby/sdk" import * as nip19 from "nostr-tools/nip19" -import {get} from "svelte/store" +import {get, derived} from "svelte/store" import type {Override, MakeOptional} from "@welshman/lib" import { first, @@ -90,6 +90,7 @@ import { getPubkeyRelays, userBlossomServerList, shouldUnwrap, + getThunkError, } from "@welshman/app" import {compressFile} from "@lib/html" import {kv, db} from "@app/core/storage" @@ -106,6 +107,9 @@ import { getSetting, userGroupList, shouldIgnoreError, + stripPrefix, + relaysMostlyRestricted, + deriveSocket, } from "@app/core/state" import {loadAlertStatuses} from "@app/core/requests" import {platform, platformName, getPushInfo} from "@app/util/push" @@ -281,12 +285,40 @@ export const attemptRelayAccess = async (url: string, claim = "") => { if (shouldIgnoreError(error)) return - if (claim) { - const ignoreClaimError = - error.includes("invalid invite code size") || error.includes("failed to validate invite code") + if (error.includes("invite code")) return "join request rejected" - if (!ignoreClaimError) return error?.replace(/^\w+: /, "") - } + return stripPrefix(error) +} + +export const deriveRelayAuthError = (url: string, claim = "") => { + // Kick off the auth process + Pool.get().get(url).auth.attemptAuth(sign) + + // Attempt to join the relay + const thunk = publishJoinRequest({url, claim}) + + return derived( + [thunk, relaysMostlyRestricted, deriveSocket(url)], + ([$thunk, $relaysMostlyRestricted, $socket]) => { + if ($socket.auth.status === AuthStatus.Forbidden && $socket.auth.details) { + return stripPrefix($socket.auth.details) + } + + if ($relaysMostlyRestricted[url]) { + return stripPrefix($relaysMostlyRestricted[url]) + } + + const error = getThunkError($thunk) + + if (error) { + const isEmptyInvite = !claim && error.includes("invite code") + + if (!shouldIgnoreError(error) && !isEmptyInvite) { + return stripPrefix(error) || "join request rejected" + } + } + }, + ) } // Deletions diff --git a/src/app/core/state.ts b/src/app/core/state.ts index 295429fc..5e7e976c 100644 --- a/src/app/core/state.ts +++ b/src/app/core/state.ts @@ -97,7 +97,6 @@ import { getTagValue, getTagValues, isRelayUrl, - makeEvent, normalizeRelayUrl, readList, verifyEvent, @@ -115,12 +114,9 @@ import { createSearch, userFollowList, ensurePlaintext, - sign, signer, makeOutboxLoader, appContext, - getThunkError, - publishThunk, deriveRelay, makeUserData, makeUserLoader, @@ -986,41 +982,7 @@ export const shouldIgnoreError = (error: string) => { return isIgnored || isAborted || isStrictNip29Relay } -export const deriveRelayAuthError = (url: string, claim = "") => { - const stripPrefix = (m: string) => m.replace(/^\w+: /, "") - - // Kick off the auth process - Pool.get().get(url).auth.attemptAuth(sign) - - // Attempt to join the relay - const thunk = publishThunk({ - event: makeEvent(RELAY_JOIN, {tags: [["claim", claim]]}), - relays: [url], - }) - - return derived( - [thunk, relaysMostlyRestricted, deriveSocket(url)], - ([$thunk, $relaysMostlyRestricted, $socket]) => { - if ($socket.auth.status === AuthStatus.Forbidden && $socket.auth.details) { - return stripPrefix($socket.auth.details) - } - - if ($relaysMostlyRestricted[url]) { - return stripPrefix($relaysMostlyRestricted[url]) - } - - const error = getThunkError($thunk) - - if (error) { - const isEmptyInvite = !claim && error.includes("invite code") - - if (!shouldIgnoreError(error) && !isEmptyInvite) { - return stripPrefix(error) || "join request rejected" - } - } - }, - ) -} +export const stripPrefix = (m: string) => m.replace(/^\w+: /, "") export type InviteData = {url: string; claim: string} diff --git a/src/routes/spaces/[relay]/+layout.svelte b/src/routes/spaces/[relay]/+layout.svelte index 37dc26b8..cc5748f9 100644 --- a/src/routes/spaces/[relay]/+layout.svelte +++ b/src/routes/spaces/[relay]/+layout.svelte @@ -9,7 +9,8 @@ import SpaceTrustRelay from "@app/components/SpaceTrustRelay.svelte" import {pushModal} from "@app/util/modal" import {setChecked} from "@app/util/notifications" - import {decodeRelay, deriveRelayAuthError, relaysPendingTrust} from "@app/core/state" + import {decodeRelay, relaysPendingTrust} from "@app/core/state" + import {deriveRelayAuthError} from "@app/core/commands" import {notifications} from "@app/util/notifications" type Props = {