refactor: extract RelayUtils.swift from AppState (Stage 1)#30
Merged
Conversation
Stage 1 of the AppState god-object split (BACKLOG High Priority). Moves connectToRelays / publishEventToRelays / fetchEventsFromRelays plus the _testOnly* DEBUG shims out of AppState.swift into a new caseless `enum RelayUtils` namespace under Shared/. Zero behavior change: - Function bodies and doc comments preserved byte-for-byte. - Silent error swallow unchanged (deferred to BACKLOG follow-up "Better error-message detail in nostrconnect Activity log"). - Actor isolation unchanged (plain async, non-isolated). Design decisions: - enum (not struct) namespace, matching Shared/LogExporter.swift. Caseless enum is uninstantiable; signals "namespace, not value type". - Drop _testOnly* wrappers entirely. They existed only because the originals were `private`; with extraction the methods are internal-by-default and tests call RelayUtils.* directly. - No Logger added. Stage 1 is structural-only; richer per-relay error reporting belongs in the existing BACKLOG follow-up. Tests: - AppStateMultiRelayHelpersTests.swift renamed to RelayUtilsTests.swift (matches Clave's "what's tested" naming convention). - 4 tests, same assertions, same inputs. Drop `let appState = AppState()` setup line — no longer needed. Verification: - xcodebuild test -skip-testing:ClaveUITests on iPhone 17 / iOS 26.4: 240 passed / 0 failed in both pre-baseline and post-refactor runs. - AppState.swift -78 lines net (2338 -> 2260). - New file 71 LOC; pbxproj +4 entries (Clave target only, NSE excluded). Stages 2-4 of the AppState split (LegacyMigrations, ProfileFetcher, NostrConnectCoordinator, ProxyClient, AccountManager, PendingApprovalCoordinator) are out of scope for this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
DocNR
added a commit
that referenced
this pull request
May 7, 2026
…31) Internal-only build for on-device verification of the AppState RelayUtils.swift extraction (#30). Bumps CURRENT_PROJECT_VERSION 63 -> 64 across all 4 targets (Clave, ClaveTests, ClaveUITests, ClaveNSE) in both Debug and Release configs. Stage 1 verification gates: - xcodebuild test passes identically pre and post (240/240) ✓ - Build 64 archives + uploads to TestFlight (this PR enables) - noStrudel (or Jumble) nostrconnect control trace shows no divergence from a build-63 baseline (gates Stage 2 start) Stages 2-4 of the AppState god-object split remain in BACKLOG; each stage gets its own refactor + bump + verify cycle. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stage 1 of the AppState god-object split — extracts three pure parallel-fanout helpers (
connectToRelays,publishEventToRelays,fetchEventsFromRelays) plus their_testOnly*DEBUG shims out ofClave/AppState.swiftinto a newShared/RelayUtils.swiftnamespace. Zero behavior change.Why this stage first
self.references), already side-effect-free, already covered by unit tests.enumnamespace, matchingShared/LogExporter.swiftprecedent) for the higher-risk stages that follow.Design decisions (locked during brainstorm)
enum RelayUtilswithstaticmethodsLogExporter.swiftprecedent; uninstantiable namespace_testOnly*wrappersprivate; with extraction the methods are internal-by-defaultstatic func ... async)LightRelayis already@unchecked SendableAppStateMultiRelayHelpersTests→RelayUtilsTestsWhat changed
Shared/RelayUtils.swift(71 LOC) — caselessenumnamespace with the threestaticasync methods. Function bodies and doc comments preserved byte-for-byte.Clave/AppState.swift— deleted lines 2261–2337 (the// MARK: - Multi-relay helperssection +#if DEBUGtest shims); updated 3 call sites inhandleNostrConnectfromconnectToRelays(...)→RelayUtils.connectToRelays(...), etc.ClaveTests/AppStateMultiRelayHelpersTests.swift→ClaveTests/RelayUtilsTests.swift— 4 tests, same assertions, dropped the now-unnecessarylet appState = AppState()setup line.Clave.xcodeproj/project.pbxproj— 4 entries added forRelayUtils.swift(Clave target only, NSE excluded since the methods are nostrconnect-handshake helpers, not signing-path code).What this PR does NOT change
Shared/orClave/AppStateLegacyMigrations,ProfileFetcher,NostrConnectCoordinator,ProxyClient,AccountManager,PendingApprovalCoordinator— each gets its own PR)Test plan
xcodebuild test -scheme Clave -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.4' -skip-testing:ClaveUITestsonmain: 240 passed / 0 failed ✅refactor/relay-utils: 240 passed / 0 failed ✅ (identical count; newRelayUtilsTestsclass replacesAppStateMultiRelayHelpersTests1:1 with same 4 tests)Follow-up PR
chore: bump pbxproj to build 64— separate PR after this one merges, matching the #27/#28 pattern. Build 64 internal-TF only; on-device verification with the new[Pair]log category from #27 will confirm no nostrconnect handshake regression.🤖 Generated with Claude Code