Skip to content

Nostr integration#1689

Merged
Tlaster merged 22 commits intomasterfrom
feature/nostr
Mar 26, 2026
Merged

Nostr integration#1689
Tlaster merged 22 commits intomasterfrom
feature/nostr

Conversation

@Tlaster
Copy link
Copy Markdown
Contributor

@Tlaster Tlaster commented Jan 12, 2026

fix #1264

@Tlaster Tlaster changed the title Nostr intergration Nostr integration Jan 12, 2026
@Tlaster Tlaster force-pushed the feature/nostr branch 2 times, most recently from 2cfe8f2 to 27ab790 Compare February 5, 2026 09:28
@Tlaster Tlaster marked this pull request as ready for review March 26, 2026 07:20
@Tlaster Tlaster requested a review from Copilot March 26, 2026 07:20
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98da150034

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +71 to +73
.credentialFlow<UiAccount.Nostr.Credential>(accountKey)
.distinctUntilChanged()
.debounce(30.minutes),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove 30-minute debounce from Nostr credential stream

Debouncing credentialFlow for 30.minutes delays the initial credential emission, so SwitchingServiceManager cannot construct a NostrService immediately; any withService call will wait for that first value and Nostr timelines/actions can sit loading for up to 30 minutes after startup (and after credential changes).

Useful? React with 👍 / 👎.

Comment thread iosApp/flare/UI/FlareRoot.swift Outdated
Comment on lines +98 to +100
// if case .success = onEnum(of: activeAccountPresenter.state.user) {
// Tab(value: "more", role: .search) {
// SecondaryTabsScreen(tabs: tabs.secondary)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore compact-width navigation to secondary tabs

In the compact-width branch, only tabs.primary are rendered and the More tab path to SecondaryTabsScreen is commented out, while Settings and secondary routes are only added in the regular-width branch; on iPhone-sized layouts this removes access to Settings and all secondary tabs.

Useful? React with 👍 / 👎.

Comment on lines +116 to +117
value.startsWith("nsec1", ignoreCase = true) ->
RustKeys.parse(raw).use { it.secretKey() }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse normalized nsec value instead of raw input

This branch checks the normalized value (after stripping nostr:/whitespace) but then parses raw; inputs like nostr:nsec1... or nsec strings with surrounding spaces will be rejected even though normalization was intended to accept them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds native Nostr support across the shared data layer and all UI targets, while refactoring platform-specific behaviors (deep links, instance detection, secondary tabs, metadata/icons) behind a new PlatformSpec abstraction.

Changes:

  • Introduces Nostr account/login, datasource, platform detection/specs, relay management, and test coverage.
  • Refactors platform-dependent logic (deep links, instance metadata, icons, secondary tabs) to use PlatformType.spec.
  • Adds settings/data export-import, pinned tabs support, and updates Android/Desktop/iOS navigation/UI to surface new capabilities (including Nostr relays).

Reviewed changes

Copilot reviewed 110 out of 124 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
shared/src/commonTest/kotlin/dev/dimension/flare/data/network/nostr/NostrServiceTest.kt Adds unit tests for Nostr account/timeline mapping.
shared/src/commonTest/kotlin/dev/dimension/flare/common/deeplink/DeepLinkMappingTest.kt Updates tests to use PlatformType.spec.deepLinkPatterns.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/screen/settings/AllTabsPresenter.kt Switches default/secondary tab generation API.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/screen/settings/AccountManagementPresenter.kt New presenter to manage accounts + ordering updates.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/screen/rss/RssListWithTabsPresenter.kt New RSS list + pin-tabs presenter wiring.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/screen/misskey/MisskeyAntennasListWithTabsPresenter.kt Migrates icon enum to UiIcon.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/screen/list/AllListWithTabsPresenter.kt Migrates icon enum to UiIcon.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/screen/bluesky/BlueskyFeedsWithTabsPresenter.kt Migrates icon enum to UiIcon.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/settings/NostrRelaysPresenter.kt Adds relay CRUD for Nostr credentials.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/login/ServiceSelectPresenter.kt Adds Nostr login state into service selection.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/login/NostrLoginPresenter.kt New Nostr login presenter (imports key, adds account).
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/login/InstanceMetadataPresenter.kt Refactors instance metadata fetching via PlatformSpec.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/home/SecondaryTabsPresenter.kt New presenter building per-account secondary tabs list.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/home/DeepLinkPresenter.kt Uses spec-provided deep link patterns.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/compose/ComposeUseCase.kt Logs compose errors to DebugRepository.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/SettingsPresenter.kt New unified presenter for settings flows + updates.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/PinTabsPresenter.kt New generic pin/unpin tabs presenter.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/ImportSettingsPresenter.kt Adds settings import from JSON export.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/ImportDataPresenter.kt Adds combined data import (DB + settings).
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/HomeTimelineWithTabsPresenter.kt Uses spec metadata + platform icon.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/HomeTabsPresenter.kt Updates secondary tab resolution API usage.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/ExportSettingsPresenter.kt Adds settings export to JSON.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/presenter/ExportDataPresenter.kt Adds combined data export (DB + settings).
shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/mapper/Nostr.kt Adds Nostr action menu mapping helpers.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiRssSource.kt Adjusts favicon/logo resolution after logoUrl removal.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiIcon.kt Expands UiIcon enum to cover nav/platform icons (incl. Nostr/X).
shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiApplication.kt Adds Nostr application mapping.
shared/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiAccount.kt Adds Nostr account + credential + datasource creation.
shared/src/commonMain/kotlin/dev/dimension/flare/model/PlatformType.kt Adds Nostr platform + introduces PlatformTypeMetadata.
shared/src/commonMain/kotlin/dev/dimension/flare/model/PlatformSpec.kt New platform spec abstraction + helpers (spec, icon, etc.).
shared/src/commonMain/kotlin/dev/dimension/flare/di/CommonModule.kt Registers NostrCache + SettingsRepository in shared DI.
shared/src/commonMain/kotlin/dev/dimension/flare/data/repository/SettingsRepository.kt New repository managing appearance/app/tab settings datastores.
shared/src/commonMain/kotlin/dev/dimension/flare/data/repository/AccountRepository.kt Adds credential update + closes datasources on removal + spec guest datasource.
shared/src/commonMain/kotlin/dev/dimension/flare/data/platform/XqtPlatformSpec.kt New X spec: deep links, secondary tabs, detector, metadata.
shared/src/commonMain/kotlin/dev/dimension/flare/data/platform/VvoPlatformSpec.kt New VVo spec: detector, metadata, secondary tabs.
shared/src/commonMain/kotlin/dev/dimension/flare/data/platform/NostrPlatformSpec.kt New Nostr spec: detector, metadata stubs.
shared/src/commonMain/kotlin/dev/dimension/flare/data/platform/MisskeyPlatformSpec.kt New Misskey spec: deep links, secondary tabs, instance metadata.
shared/src/commonMain/kotlin/dev/dimension/flare/data/platform/MastodonPlatformSpec.kt New Mastodon spec: deep links, secondary tabs, instance metadata, guest DS.
shared/src/commonMain/kotlin/dev/dimension/flare/data/platform/BlueskyPlatformSpec.kt New Bluesky spec: deep links, secondary tabs, detector.
shared/src/commonMain/kotlin/dev/dimension/flare/data/network/xqt/XQTPlatformDetector.kt Adds X host-based platform detector.
shared/src/commonMain/kotlin/dev/dimension/flare/data/network/vvo/VVOPlatformDetector.kt Adds VVo host-based platform detector.
shared/src/commonMain/kotlin/dev/dimension/flare/data/network/nostr/NostrPlatformDetector.kt Adds Nostr detector for pseudo-host.
shared/src/commonMain/kotlin/dev/dimension/flare/data/network/nodeinfo/PlatformDetector.kt New interface for platform detection strategy.
shared/src/commonMain/kotlin/dev/dimension/flare/data/network/nodeinfo/NodeInfoService.kt Refactors platform detection to use detectors + normalizes host.
shared/src/commonMain/kotlin/dev/dimension/flare/data/network/misskey/MisskeyPlatformDetector.kt Adds Misskey detector via nodeinfo + meta probing.
shared/src/commonMain/kotlin/dev/dimension/flare/data/network/mastodon/MastodonPlatformDetector.kt Adds Mastodon detector via nodeinfo + instance probing.
shared/src/commonMain/kotlin/dev/dimension/flare/data/network/bluesky/BlueskyPlatformDetector.kt Adds Bluesky detector via server description.
shared/src/commonMain/kotlin/dev/dimension/flare/data/model/SettingsExport.kt New model for settings export payload.
shared/src/commonMain/kotlin/dev/dimension/flare/data/model/DataExport.kt New model for combined data export payload.
shared/src/commonMain/kotlin/dev/dimension/flare/data/model/AppearanceSettings.kt Moves LocalAppearanceSettings out + tweaks defaults/visibility.
shared/src/commonMain/kotlin/dev/dimension/flare/data/datastore/AppDataStore.kt Adjusts visibility/accessors for shared datastore fields.
shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/nostr/StatusDetailRemoteMediator.kt Adds Nostr status detail/context paging loader.
shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/nostr/NostrLoader.kt Adds Nostr user/relation/post loader wiring.
shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/nostr/NostrDataSource.kt Implements Nostr authenticated datasource + compose/actions/timelines.
shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/nostr/NostrCache.kt Adds cache interface + DB-backed implementation for Nostr.
shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/microblog/handler/UserHandler.kt Tightens handler constructor visibility.
shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/microblog/RecommendInstancePagingSource.kt Refactors instance icons + adds Nostr recommended instance.
shared/src/commonMain/kotlin/dev/dimension/flare/data/datasource/microblog/PostEvent.kt Adds Nostr post events (like/repost/report).
shared/src/commonMain/kotlin/dev/dimension/flare/data/database/cache/mapper/Microblog.kt Expands user extraction across nested timeline content.
shared/src/commonMain/kotlin/dev/dimension/flare/common/deeplink/DeepLinkMapping.kt Removes old pattern generator (now in PlatformSpecs).
shared/src/commonMain/kotlin/dev/dimension/flare/common/SwitchingServiceManager.kt Adds service manager for credential-driven service swapping.
shared/build.gradle.kts Adds Nostr SDK KMP dependency.
iosApp/flare/UI/Screen/SettingsScreen.swift Moves some settings links out of this screen.
iosApp/flare/UI/Screen/SecondaryTabsScreen.swift Reworks “More/secondary” UI into presenter-driven accounts menu.
iosApp/flare/UI/Screen/NostrRelaysScreen.swift Adds iOS UI to manage Nostr relays.
iosApp/flare/UI/Screen/HomeTimelineScreen.swift Adds secondary menu entry + tab selector menu in toolbar.
iosApp/flare/UI/Screen/GroupConfigScreen.swift Updates icon picker to use UiIcon.
iosApp/flare/UI/Screen/DiscoverScreen.swift Moves account selector into toolbar menu.
iosApp/flare/UI/Screen/AccountManagementScreen.swift Adds Nostr “Manage relays” navigation actions.
iosApp/flare/UI/Route/TabItemView.swift Updates HomeTimelineScreen initializer signature.
iosApp/flare/UI/Route/Router.swift Allows .secondaryMenu as a presented route.
iosApp/flare/UI/Route/Route.swift Adds routes for Nostr relays + secondary menu.
iosApp/flare/UI/FlareRoot.swift Refactors tab/root composition; removes old “More” tab path.
iosApp/flare/UI/Component/TabIcon.swift Updates material icon mapping to use UiIcon.
iosApp/flare/UI/Component/Status/StatusView.swift Adds Nostr platform indicator in status header.
iosApp/flare/UI/Component/Status/StatusActionView.swift Expands UiIcon → SF/asset name mapping (incl. Nostr).
iosApp/flare/Assets.xcassets/fa-nostr.symbolset/fa-nostr.symbols.svg Adds Nostr icon asset.
iosApp/flare/Assets.xcassets/fa-nostr.symbolset/Contents.json Registers Nostr icon asset.
iosApp/flare/Assets.xcassets/fa-chevron-down.symbolset/Contents.json Registers chevron-down symbol asset.
gradle/libs.versions.toml Adds Nostr SDK + ktor websockets to version catalog/bundle.
desktopApp/src/main/kotlin/dev/dimension/flare/ui/screen/settings/SettingsScreen.kt Adds Nostr “Manage relays” context menu entry.
desktopApp/src/main/kotlin/dev/dimension/flare/ui/screen/settings/NostrRelaysScreen.kt Adds Desktop UI to manage Nostr relays.
desktopApp/src/main/kotlin/dev/dimension/flare/ui/screen/list/ListScreen.kt Migrates icon enum to UiIcon.
desktopApp/src/main/kotlin/dev/dimension/flare/ui/screen/home/GroupConfigScreen.kt Migrates icon picker to UiIcon.
desktopApp/src/main/kotlin/dev/dimension/flare/ui/screen/home/EditTabDialog.kt Switches icon grid orientation/layout.
desktopApp/src/main/kotlin/dev/dimension/flare/ui/screen/feeds/FeedScreen.kt Migrates icon enum to UiIcon.
desktopApp/src/main/kotlin/dev/dimension/flare/ui/route/Router.kt Adds NostrRelays route + migrates icons to UiIcon.
desktopApp/src/main/kotlin/dev/dimension/flare/ui/route/Route.kt Adds Desktop route for Nostr relays screen.
desktopApp/src/main/kotlin/dev/dimension/flare/Main.kt Removes composeUiModule from Koin wiring.
desktopApp/src/main/composeResources/values/strings.xml Adds Nostr relay management strings.
compose-ui/src/iosMain/kotlin/dev/dimension/flare/ui/controllers/ComposeUIHelper.kt Removes composeUiModule registration (uses shared modules only).
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/screen/settings/EditTabPresenter.kt Migrates available icons to UiIcon.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/screen/login/ServiceSelectionScreenContent.kt Adds Nostr login UI + uses spec-based icons/agreement URL.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/screen/login/SelectionPresenter.kt Adds Nostr input presenter state.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/screen/login/NostrInputPresenter.kt Adds presenter for Nostr key input.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/model/UiListExt.kt Migrates fallback icons to UiIcon.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/model/PlatformTypeIcon.kt Adds platform brand icon mapping incl. Nostr.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/icons/MisskeyIcon.kt Adds Nostr icon vector + refactors Misskey vector building.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/component/status/UiTimelineComponent.kt Imports icon mapping helper for timeline UI.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/component/status/CommonStatusComponent.kt Uses platform brandIcon; moves UiIcon mapping out.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/component/UiIconExt.kt Centralizes UiIcon → ImageVector mapping.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/ui/component/TabIcon.kt Uses new UiIcon mapping + removes old MaterialIcon mapping.
compose-ui/src/commonMain/kotlin/dev/dimension/flare/di/ComposeUiModule.kt Removes redundant DI module (now in shared commonModule).
compose-ui/src/commonMain/kotlin/dev/dimension/flare/data/model/LocalAppearanceSettings.kt Restores composition local for appearance settings in compose-ui.
compose-ui/src/commonMain/composeResources/values/strings.xml Adds Nostr login strings/hints.
app/src/main/res/values/strings.xml Adds Nostr relay management strings (Android).
app/src/main/java/dev/dimension/flare/ui/screen/settings/SettingsSelectEntryBuilder.kt Adds navigation entry for Nostr relays screen.
app/src/main/java/dev/dimension/flare/ui/screen/settings/NostrRelaysScreen.kt Adds Android UI to manage Nostr relays.
app/src/main/java/dev/dimension/flare/ui/screen/settings/GuestSettingScreen.kt Uses platform icon vectors instead of logo URLs.
app/src/main/java/dev/dimension/flare/ui/screen/settings/EditTabDialog.kt Switches icon grid orientation/layout.
app/src/main/java/dev/dimension/flare/ui/screen/settings/AccountsScreen.kt Adds “Manage relays” menu item for Nostr accounts.
app/src/main/java/dev/dimension/flare/ui/screen/rss/RssEntryBuilder.kt Migrates icons to UiIcon.
app/src/main/java/dev/dimension/flare/ui/screen/misskey/MisskeyEntryBuilder.kt Migrates icons to UiIcon.
app/src/main/java/dev/dimension/flare/ui/screen/list/ListEntryBuilder.kt Migrates icons to UiIcon.
app/src/main/java/dev/dimension/flare/ui/screen/home/GroupConfigScreen.kt Switches icon grid orientation + migrates to UiIcon.
app/src/main/java/dev/dimension/flare/ui/route/Route.kt Adds Android route for Nostr relays settings.
app/src/main/java/dev/dimension/flare/App.kt Removes composeUiModule from Koin wiring.
app/build.gradle.kts Adds JNA dependency (AAR) to Android app.
.github/workflows/ios.yml Temporarily disables running allTests in iOS CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +390 to +421
override fun nextActionMenu(): ActionMenu.Item =
ActionMenu.nostrRepost(
statusKey = postKey,
repostEventId =
if (repostEventId == null) {
""
} else {
null
},
count = (count + if (repostEventId == null) 1 else -1).coerceAtLeast(0),
accountKey = accountKey,
)
}

@Serializable
data class Like(
override val postKey: MicroBlogKey,
val reactionEventId: String?,
val count: Long = 0,
val accountKey: MicroBlogKey,
) : Nostr,
UpdatePostActionMenuEvent {
override fun nextActionMenu(): ActionMenu.Item =
ActionMenu.nostrLike(
statusKey = postKey,
reactionEventId =
if (reactionEventId == null) {
""
} else {
null
},
count = (count + if (reactionEventId == null) 1 else -1).coerceAtLeast(0),
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nextActionMenu() uses an empty string (""") as a placeholder event id to represent the toggled state. If the user taps again before the real event id arrives, the next PostEvent.Nostr.* will carry repostEventId == "" / reactionEventId == "", and NostrDataSource.handle() will treat it as non-null and attempt to delete a status with an empty id. Use an explicit boolean (e.g., reposted/liked) for optimistic UI, or keep the id nullable and add a separate pending flag; at minimum, avoid emitting "" and ensure handlers treat blank ids as null.

Copilot uses AI. Check for mistakes.
Comment on lines +70 to +74
accountRepository
.credentialFlow<UiAccount.Nostr.Credential>(accountKey)
.distinctUntilChanged()
.debounce(30.minutes),
ioScope,
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debounce(30.minutes) on the credential flow will delay the initial credential emission (and therefore NostrService creation/connection) by up to 30 minutes, effectively breaking Nostr timelines/login. If the goal is to avoid rapid reconnects after edits, consider removing debounce or using a short debounce (hundreds of ms / a few seconds) and/or applying it only after the initial value (e.g., drop(1) before debounce).

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +16
internal data object NostrPlatformDetector : PlatformDetector {
override suspend fun detect(host: String): NodeData? {
if (!host.equals("nostr", ignoreCase = true)) {
return null
}
return NodeData(
host = host,
platformType = PlatformType.Nostr,
software = PlatformType.Nostr.name,
compatibleMode = false,
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NostrPlatformDetector doesn't override priority, so it defaults to 0 and will be tried after higher-priority network detectors. For the special pseudo-host "nostr", this means unnecessary network calls (and potentially long failures) before selecting Nostr. Set an explicit high priority and/or consider short-circuiting earlier in NodeInfoService.detectPlatformType for host == "nostr".

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +37
override fun close() {
job.cancel()
scope.cancel()
current.value?.service?.close()
}
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

close() cancels scope before any pending "retired" close coroutines (launched in init) can finish, which can leak previously-created services during shutdown/switches. Consider closing services deterministically in close() (e.g., capture current/retired entries under the mutex and close them in a finally, or don't cancel the scope until after pending drains/closes complete).

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +53
override val relays = credential.map { it.relays.toImmutableList() }

override fun addRelay(relay: String) {
credential.onSuccess { credential ->
if (relay in credential.relays) return
val newRelays = credential.relays + relay
val newCredential = credential.copy(relays = newRelays)
accountRepository.updateCredential(
accountKey = accountKey,
credential = newCredential,
)
}
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addRelay/removeRelay persist whatever string the user enters. Since NostrService later parses relay strings during service creation, an invalid relay URL can throw and break NostrService initialization (potentially taking the datasource offline). Validate and normalize relay URLs before saving (trim, ensure ws:///wss://, parse with runCatching, de-dup), and consider exposing an error state so the UI can surface validation failures.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/ios.yml
run: ./gradlew allTests
# temporarily disabled due to https://github.com/rust-nostr/nostr-sdk-ffi/issues/72
# - name: Run Tests
# run: ./gradlew allTests
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow change disables ./gradlew allTests entirely for iOS CI, which removes a key regression signal for unrelated changes. If possible, scope the disablement to only the affected Nostr-related tests/targets (or gate behind a condition) and/or add a follow-up task to re-enable once the upstream issue is fixed.

Suggested change
# run: ./gradlew allTests
# run: ./gradlew allTests
- name: Track follow-up to re-enable Gradle allTests
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const issueTitle = 'Re-enable ./gradlew allTests in iOS CI once nostr-sdk-ffi issue #72 is fixed';
const { owner, repo } = context.repo;
// Search for an existing open issue with this exact title
const searchQuery = `repo:${owner}/${repo} "${issueTitle}" in:title type:issue state:open`;
const searchResult = await github.rest.search.issuesAndPullRequests({ q: searchQuery });
if (searchResult.data.items.length === 0) {
await github.rest.issues.create({
owner,
repo,
title: issueTitle,
body: [
'The `./gradlew allTests` step in `.github/workflows/ios.yml` is currently disabled',
'due to the upstream issue [`rust-nostr/nostr-sdk-ffi#72`](https://github.com/rust-nostr/nostr-sdk-ffi/issues/72).',
'',
'Once that upstream issue is resolved, re-enable the Gradle `allTests` step in the iOS CI workflow',
'to restore full regression coverage for unrelated changes.'
].join('\n')
});
}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f22f6d00b8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Immutable
@Serializable
public enum class PlatformType {
Nostr,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve protobuf enum ordering for PlatformType

Placing Nostr before existing entries renumbers all serialized PlatformType enum values. GuestDataSerializer still reads guest_data.pb with ProtoBuf (shared/.../data/datastore/model/GuestData.kt), so previously persisted guest configs can deserialize to the wrong platform (e.g., old Mastodon ordinal mapping to Nostr), and guest mode then routes to NostrPlatformSpec.guestDataSource, which throws UnsupportedOperationException. This creates upgrade-time breakage for users with stored guest settings until data is reset.

Useful? React with 👍 / 👎.

Comment on lines +47 to +48
val newRelays = credential.relays + relay
val newCredential = credential.copy(relays = newRelays)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate relay URL before saving it to credentials

addRelay stores arbitrary non-empty input directly into persisted Nostr credentials, but relay strings are later parsed with RustRelayUrl.parse during NostrService creation. A malformed relay entered once can make service initialization fail in the switching manager path, leaving that Nostr account unable to load timelines or perform actions until the bad value is removed out-of-band. Input should be validated/normalized before persisting.

Useful? React with 👍 / 👎.

@Tlaster Tlaster merged commit 3836d32 into master Mar 26, 2026
10 checks passed
@Tlaster Tlaster deleted the feature/nostr branch March 26, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add native Nostr protocol support in Flare, enabling users to publish and consume content via Nostr relays

2 participants