Skip to content

App transfer to the Open Home Foundation account - #6113

Draft
bgoncal wants to merge 67 commits into
mainfrom
feature/app-account-migration
Draft

bgoncal wants to merge 67 commits into
mainfrom
feature/app-account-migration

Conversation

@bgoncal

@bgoncal bgoncal commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

AI Policy

Select exactly one option that describes AI usage in this contribution:

  • I have not used AI for this contribution.
  • AI assistance was used for this contribution.
  • AI fully generated the code for this contribution, but I've reviewed and understood it before submitting and will respond without AI during review.

Summary

The app moves to the Open Home Foundation Apple account under a new bundle identifier, so users end up with two apps side by side. This adds an in-app transfer between them: the existing app packages its servers, sign-ins, settings and mTLS identities into an encrypted payload, hands it over through the pasteboard and a custom URL scheme, and the new app imports it. The existing app then refuses to set up new servers, points at the new app, and can erase itself once the transfer is verified.

The Apple account is selected through configuration (Configuration/Account.xcconfig) instead of a branch, so the same code builds either app.

Screenshots

Snapshot references for every transfer screen, light and dark, are under Tests/App/Onboarding/Migration/__Snapshots__/AppMigrationScreens.test/.

Link to pull request in Documentation repository

Documentation: home-assistant/companion.home-assistant#

Any other notes

Draft while the remaining pieces land:

  • Apple has not yet granted these capabilities to the new App IDs, so their flags stay off in Configuration/Accounts/ohf.xcconfig: push provider (app-push-provider, needed on io.home-assistant.app and io.home-assistant.app.PushProvider, blocks the TestFlight upload), Critical Alerts on the PushProvider App ID (it currently carries Critical Messaging), Thread network credentials, user-assigned device name. CarPlay is granted.
  • Documentation PR in companion.home-assistant still to be opened.
  • The transfer strings exist in English only; translations go through Lokalise.
  • Snapshot references for the transfer screens, the alert component, the QR components and the connection URL screen were recorded locally on iOS 27.x and may need re-recording on the CI runtime.
  • The migration E2E tests (Tests/UI/MigrationE2ETests.swift) run only locally with two installed builds and a reachable server; they are not wired into CI.
  • The Xcode 27.2 RC simulator cannot show the "Allow Paste" prompt, so the local E2E run pre-authorises the pasteboard permission in the simulator.
  • Replace the custom URL schemes used for the hand-off (homeassistant-ohf, homeassistant-nc) with Universal Links.
  • Open product decision: confirm before a transfer wipes a new app that already has servers.
  • Follow-up when Let a restored device register as a new device #6088 merges: keep the imported registrations through RegistrationOwnership after the import.
  • The PushProvider xcscheme still carries the OHF debug bundle identifier; xcscheme files cannot read build settings.

# Conflicts:
#	Sources/App/Frontend/IncomingURLHandler.swift
#	Sources/App/Resources/en.lproj/Localizable.strings
#	Sources/App/Settings/Kiosk/KioskView.swift
#	Sources/Shared/Resources/Swiftgen/Strings.swift
@bgoncal
bgoncal requested a balanced review from Copilot October 22, 2026 12:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved entitlement mismatches, destructive URL handling, secret logging, and incomplete credential transfers block approval.

15 open issues
What changed in this PR

Adds an encrypted, on-device setup transfer from the existing Home Assistant app to the Open Home Foundation app, while allowing both Apple accounts to build from the same codebase.

Changes:

  • Adds transfer packaging, import, handoff persistence, onboarding screens, and mTLS identity export/import.
  • Integrates migration announcements, permissions, and connection suspension into the app lifecycle.
  • Makes identifiers, signing, Firebase configuration, and distribution account-specific.
  • Adds localized transfer text, reusable UI components, and migration tests.
File Description
Tests/​Shared/​DesignSystem/​Gallery/​FrontendComponentMapping.test.swift Classifies section pills as app-specific components.
Tests/​App/​Onboarding/​Migration/​ClientIdentityExport.test.swift Tests mTLS identity export/import round trips.
Tests/​App/​Onboarding/​Migration/​AppMigrationScreens.test.swift Adds migration-screen snapshot coverage.
Tests/​App/​Onboarding/​Migration/​AppMigrationLinkTests.swift Tests migration links, encryption, and handoff persistence.
Sources/​WatchWidgets/​WatchWidgetConstants.swift Removes the legacy bundle-identifier fallback.
Sources/​WatchApp/​Info.plist Parameterizes display and companion identifiers.
Sources/​Shared/​Notifications/​LocalPush/​LocalPushEvent.swift Uses the configured application identifier.
Sources/​Shared/​Environment/​CrashReporter.swift Reads the official bundle prefix from configuration.
Sources/​Shared/​Environment/​AppConstants.swift Resolves configured background-task identifiers.
Sources/​Shared/​API/​Webhook/​Networking/​WebhookManager.swift Adds webhook-request suspension guards.
Sources/​Shared/​API/​HAAPI.swift Adds connection-suspension checks.
Sources/​HANetworking/​Sources/​ClientIdentityExport.swift Defines transferable mTLS identity material.
Sources/​HANetworking/​Sources/​ClientCertificateManager+Export.swift Implements mTLS identity export and restoration.
Sources/​HANetworking/​Sources/​ClientCertificate.swift Exposes certificate-chain helpers within the module.
Sources/​HADesignSystem/​Sources/​Gallery/​DesignSystemComponent.swift Registers section-pill gallery variants.
Sources/​HADesignSystem/​Sources/​Components/​HASectionPill.swift Adds reusable capsule-shaped section headers.
Sources/​HADesignSystem/​Sources/​Components/​HAAlertView.swift Updates alert alignment, spacing, and shape.
Sources/​HADesignSystem/​Sources/​Components/​CardView.swift Supports configurable card corner radii.
Sources/​App/​WhatsNew/​WhatsNewCatalog.swift Suppresses release announcements during migration messaging.
Sources/​App/​Utilities/​RemindersSync/​RemindersSyncBackgroundRefresher.swift Uses the configured background-task identifier.
Sources/​App/​Settings/​Settings/​SettingsView.swift Adds access to migration from Settings.
Sources/​App/​Settings/​Settings/​SettingsItem.swift Defines the migration settings entry.
Sources/​App/​Settings/​Settings/​ServersListView.swift Adds an add-server accessibility identifier.
Sources/​App/​Settings/​Sensors/​Permissions/​SensorPermissionsViewModel.swift Reuses permission-to-Settings destination mapping.
Sources/​App/​Settings/​Sensors/​Permissions/​SensorPermission.swift Exposes permission-specific Settings destinations.
Sources/​App/​Settings/​Kiosk/​ConditionalContainerView.swift Adds handoff-aware kiosk presentation logic.
Sources/​App/​Resources/​pt-BR.lproj/​Localizable.strings Adds Brazilian Portuguese transfer text.
Sources/​App/​Resources/​Info.plist Registers migration schemes and account-specific metadata.
Sources/​App/​Resources/​es.lproj/​Localizable.strings Adds Spanish transfer text.
Sources/​App/​Resources/​es-MX.lproj/​Localizable.strings Adds Mexican Spanish transfer text.
Sources/​App/​Resources/​en.lproj/​Localizable.strings Defines English transfer strings.
Sources/​App/​Resources/​en-GB.lproj/​Localizable.strings Adds British English transfer text.
Sources/​App/​Onboarding/​Views/​CheckmarkDrawOnView.swift Makes success illustrations configurable.
Sources/​App/​Onboarding/​Steps/​Welcome/​OnboardingWelcomeView.swift Offers transfer from the existing app.
Sources/​App/​Onboarding/​Steps/​Permissions/​OnboardingPermissionsNavigationView.swift Adapts success-screen layout.
Sources/​App/​Onboarding/​Migration/​AppMigrationTransferredItem.swift Defines displayed transfer categories.
Sources/​App/​Onboarding/​Migration/​AppMigrationSummary.swift Summarizes transferred servers and permissions.
Sources/​App/​Onboarding/​Migration/​AppMigrationSuccessView.swift Animates the completion-screen transition.
Sources/​App/​Onboarding/​Migration/​AppMigrationSessionStore.swift Persists pending and completed transfer sessions.
Sources/​App/​Onboarding/​Migration/​AppMigrationSession.swift Generates session identifiers and encryption keys.
Sources/​App/​Onboarding/​Migration/​AppMigrationRole.swift Determines app roles and peer addressing.
Sources/​App/​Onboarding/​Migration/​AppMigrationProgressView.swift Displays staged transfer progress.
Sources/​App/​Onboarding/​Migration/​AppMigrationProgressScript.swift Defines progress narration and timing.
Sources/​App/​Onboarding/​Migration/​AppMigrationPermissionsViewModel.swift Tracks and requests destination-app permissions.
Sources/​App/​Onboarding/​Migration/​AppMigrationPermissionsView.swift Presents permission reauthorization controls.
Sources/​App/​Onboarding/​Migration/​AppMigrationPayload.swift Defines the serialized setup-transfer payload.
Sources/​App/​Onboarding/​Migration/​AppMigrationPasteboard.swift Exchanges expiring, device-local encrypted payloads.
Sources/​App/​Onboarding/​Migration/​AppMigrationOverviewView.swift Explains transfer contents and follow-up steps.
Sources/​App/​Onboarding/​Migration/​AppMigrationNoServersView.swift Redirects unconfigured previous-app users to the new app.
Sources/​App/​Onboarding/​Migration/​AppMigrationLink.swift Parses and generates migration URLs.
Sources/​App/​Onboarding/​Migration/​AppMigrationKeychainStore.swift Maps transferable Keychain services.
Sources/​App/​Onboarding/​Migration/​AppMigrationItemRow.swift Renders transfer inventory rows.
Sources/​App/​Onboarding/​Migration/​AppMigrationIntroView.swift Introduces the setup-transfer flow.
Sources/​App/​Onboarding/​Migration/​AppMigrationImportView.swift Displays import progress and failure states.
Sources/​App/​Onboarding/​Migration/​AppMigrationImportState.swift Models import-screen phases.
Sources/​App/​Onboarding/​Migration/​AppMigrationImporter.swift Restores transferred databases, settings, and credentials.
Sources/​App/​Onboarding/​Migration/​AppMigrationHaptics.swift Centralizes transfer haptic feedback.
Sources/​App/​Onboarding/​Migration/​AppMigrationHandoffStore.swift Persists the previous app’s handoff state.
Sources/​App/​Onboarding/​Migration/​AppMigrationHandoffPhase.swift Models persistent handoff phases.
Sources/​App/​Onboarding/​Migration/​AppMigrationGrantedPermissions.swift Collects existing device-permission grants.
Sources/​App/​Onboarding/​Migration/​AppMigrationGetNewAppView.swift Guides installation before transfer.
Sources/​App/​Onboarding/​Migration/​AppMigrationFollowUpItem.swift Defines post-transfer setup tasks.
Sources/​App/​Onboarding/​Migration/​AppMigrationFlowView.swift Connects import, completion, and permission screens.
Sources/​App/​Onboarding/​Migration/​AppMigrationExportView.swift Presents export and post-handoff actions.
Sources/​App/​Onboarding/​Migration/​AppMigrationExportState.swift Models export-screen phases.
Sources/​App/​Onboarding/​Migration/​AppMigrationExporter.swift Packages configuration and credentials for transfer.
Sources/​App/​Onboarding/​Migration/​AppMigrationExportContainerView.swift Binds export presentation to coordinator state.
Sources/​App/​Onboarding/​Migration/​AppMigrationError.swift Defines localized transfer failures.
Sources/​App/​Onboarding/​Migration/​AppMigrationCrypto.swift Encrypts and authenticates payloads with AES-GCM.
Sources/​App/​Onboarding/​Migration/​AppMigrationCompleteView.swift Presents completion, source erasure, and next steps.
Sources/​App/​Onboarding/​Migration/​AppMigrationAnnouncementView.swift Announces the account transition and transfer entry point.
Sources/​App/​Onboarding/​Migration/​AppMigrationAnnouncementItem.swift Models announcement details.
Sources/​App/​Onboarding/​Migration/​AppMigrationAnnouncement.swift Controls announcement eligibility and store links.
Sources/​App/​Onboarding/​Container/​OnboardingNavigationView.swift Adds migration routing and previous-app onboarding restrictions.
Sources/​App/​Onboarding/​API/​OnboardingDestination.swift Adds the migration navigation destination.
Sources/​App/​Notifications/​NotificationManagerLocalPushInterfaceExtension.swift Excludes servers while connections are suspended.
Sources/​App/​Frontend/​WebView/​HomeAssistantView/​LaunchMessagesState.swift Queues the migration launch announcement.
Sources/​App/​Frontend/​WebView/​HomeAssistantView/​HomeAssistantView.swift Presents the migration announcement sheet.
Sources/​App/​Frontend/​IncomingURLHandler.swift Routes incoming migration links.
Sources/​App/​Container/​OnboardingStateObservable.swift Prioritizes the persisted handoff screen.
Sources/​App/​Container/​ContainerView.swift Hosts migration export content.
Sources/​App/​BackgroundRefreshManager.swift Uses the configured refresh-task identifier.
Sources/​App/​AppDelegate.swift Restores suspension state and adjusts push setup.
Sources/​App/​Accessibility/​AccessibilityIdentifier.swift Defines migration UI automation identifiers.
HomeAssistant.xcodeproj/​xcshareddata/​xcschemes/​Extensions-PushProvider.xcscheme Targets the OHF debug application.
fastlane/​lanes/​testing.rb Selects account-specific symbol downloads.
fastlane/​lanes/​setup.rb Initializes account-aware Fastlane settings.
fastlane/​lanes/​provisioning.rb Uses account-specific provisioning directories.
fastlane/​lanes/​local_distribution.rb Checks profiles in the selected account directory.
fastlane/​lanes/​account.rb Resolves account settings from xcconfig files.
fastlane/​Fastfile Loads account-resolution helpers.
fastlane/​Deliverfile Removes the fixed application identifier.
fastlane/​Appfile Reads the selected application identifier.
Configuration/​Scripts/​fix_xcode_12.5_target_platform_issues.sh Parameterizes generated helper bundle identifiers.
Configuration/​Scripts/​copy_firebase_configuration.sh Copies account-specific Firebase configuration.
Configuration/​HomeAssistant.xcconfig Derives shared settings from the selected account.
Configuration/​HomeAssistant.release.xcconfig Selects account-specific release provisioning profiles.
Configuration/​HomeAssistant.debug.xcconfig Configures account-aware debug naming and signing.
Configuration/​Firebase/​ohf/​GoogleService-Info-Release.plist Adds OHF release Firebase configuration.
Configuration/​Firebase/​ohf/​GoogleService-Info-Debug.plist Adds OHF debug Firebase configuration.
Configuration/​Firebase/​nabu-casa/​GoogleService-Info-Release.plist Stores legacy release Firebase configuration by account.
Configuration/​Firebase/​nabu-casa/​GoogleService-Info-Debug.plist Stores legacy debug Firebase configuration by account.
Configuration/​Entitlements/​WatchWidgets.entitlements Parameterizes Watch widget sharing entitlements.
Configuration/​Entitlements/​WatchApp.entitlements Parameterizes Watch app sharing entitlements.
Configuration/​Entitlements/​Extension-ios.entitlements Parameterizes iOS extension sharing entitlements.
Configuration/​Entitlements/​Extension-catalyst.entitlements Parameterizes Catalyst extension sharing entitlements.
Configuration/​Entitlements/​App-ios.entitlements Parameterizes iOS app sharing entitlements.
Configuration/​Entitlements/​App-catalyst.entitlements Parameterizes Catalyst app sharing entitlements.
Configuration/​Accounts/​ohf.xcconfig Defines OHF identity, capabilities, and signing settings.
Configuration/​Accounts/​nabu-casa.xcconfig Defines legacy identity, capabilities, and signing settings.
Configuration/​Account.xcconfig Selects OHF as the default account.
.gitignore Excludes local account overrides.
.github/​workflows/​distribute.yml Selects distribution accounts and corresponding secrets.

Review effort: Balanced

Comment thread Sources/Shared/API/HAAPI.swift Resolved
The app group entitlement is derived from an explicit lowercase base
per account, since the Nabu Casa bundle identifier is mixed case. A
transfer started by the existing app only wipes what the new app holds
once the payload has been opened and matched to the session, migration
links are parsed without trapping on repeated parameters, and their
key and session values are redacted from URL logs. Keychain and
identity restores fail the import instead of being logged away, an
identity that cannot be exported fails the export, unknown keychain
stores decode and are skipped, the permission snapshot really stops at
its budget, and the hand-off phase in the app group suspends
connections from every process of the app. Confirmations on the
onboarding scaffold's secondary action are presented by that button.
Translated strings are left to Lokalise.
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Unused L10n strings detected

Found 2 unused localization strings in the codebase.

Click to see details
Parsing Strings.swift...
Found 3181 L10n strings

Reading all Swift source code...
Read 14528776 characters of Swift code

Checking for unused strings...
Checked 100/3181 strings...
Checked 200/3181 strings...
Checked 300/3181 strings...
Checked 400/3181 strings...
Checked 500/3181 strings...
Checked 600/3181 strings...
Checked 700/3181 strings...
Checked 800/3181 strings...
Checked 900/3181 strings...
Checked 1000/3181 strings...
Checked 1100/3181 strings...
Checked 1200/3181 strings...
Checked 1300/3181 strings...
Checked 1400/3181 strings...
Checked 1500/3181 strings...
Checked 1600/3181 strings...
Checked 1700/3181 strings...
Checked 1800/3181 strings...
Checked 1900/3181 strings...
Checked 2000/3181 strings...
Checked 2100/3181 strings...
Checked 2200/3181 strings...
Checked 2300/3181 strings...
Checked 2400/3181 strings...
Checked 2500/3181 strings...
Checked 2600/3181 strings...
Checked 2700/3181 strings...
Checked 2800/3181 strings...
Checked 2900/3181 strings...
Checked 3000/3181 strings...
Checked 3100/3181 strings...

================================================================================
UNUSED STRINGS REPORT
================================================================================

Found 2 unused strings:


SETTINGS:
  - L10n.Settings.ConnectionSection.connectingVia
    Key: settings.connection_section.connecting_via
    Line: 5694
  - L10n.Settings.ConnectionSection.loggedInAs
    Key: settings.connection_section.logged_in_as
    Line: 5702

================================================================================
Total unused: 2
================================================================================

================================================================================
Copy-paste these keys into the "Lokalise: Delete Keys" workflow (keys input):
================================================================================
settings.connection_section.connecting_via,settings.connection_section.logged_in_as

To remove them, run the
Lokalise: Delete Keys
workflow — it deletes the keys from Lokalise and opens a PR removing them from
Localizable.strings and regenerating Strings.swift. Copy-paste these keys into the keys input:

settings.connection_section.connecting_via,settings.connection_section.logged_in_as

@codecov

codecov Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.98473% with 126 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.65%. Comparing base (c7c8afa) to head (285df28).

Files with missing lines Patch % Lines
...arding/Migration/AppMigrationPermissionsView.swift 80.00% 14 Missing ⚠️
...pp/Onboarding/Migration/AppMigrationFlowView.swift 76.36% 13 Missing ⚠️
...nboarding/Container/OnboardingNavigationView.swift 66.66% 9 Missing ⚠️
...igration/AppMigrationCoordinatorDependencies.swift 64.00% 9 Missing ⚠️
...boarding/Migration/AppMigrationGetNewAppView.swift 82.69% 9 Missing ⚠️
...g/Migration/AppMigrationPermissionsViewModel.swift 68.96% 9 Missing ⚠️
.../Onboarding/Migration/AppMigrationExportView.swift 90.27% 7 Missing ⚠️
...nboarding/Migration/AppMigrationOverviewView.swift 92.55% 7 Missing ⚠️
Sources/App/AppDelegate.swift 0.00% 6 Missing ⚠️
...Onboarding/Migration/AppMigrationCoordinator.swift 97.73% 6 Missing ⚠️
... and 21 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6113      +/-   ##
==========================================
+ Coverage   59.06%   59.65%   +0.59%     
==========================================
  Files        1299     1335      +36     
  Lines       86077    87580    +1503     
==========================================
+ Hits        50840    52245    +1405     
- Misses      35237    35335      +98     
Files with missing lines Coverage Δ
Sources/App/BackgroundRefreshManager.swift 0.00% <ø> (ø)
...rces/App/Container/OnboardingStateObservable.swift 76.61% <100.00%> (+4.19%) ⬆️
...tificationManagerLocalPushInterfaceExtension.swift 94.75% <100.00%> (+0.03%) ⬆️
...ces/App/Onboarding/API/OnboardingDestination.swift 63.04% <100.00%> (-0.60%) ⬇️
...nboarding/Migration/AppMigrationAnnouncement.swift 100.00% <100.00%> (ø)
...nboarding/Migration/AppMigrationCompleteView.swift 100.00% <100.00%> (ø)
...s/App/Onboarding/Migration/AppMigrationError.swift 100.00% <100.00%> (ø)
...nboarding/Migration/AppMigrationFollowUpItem.swift 100.00% <100.00%> (ø)
...nboarding/Migration/AppMigrationHandoffStore.swift 100.00% <100.00%> (ø)
...App/Onboarding/Migration/AppMigrationHaptics.swift 100.00% <100.00%> (ø)
... and 54 more

... and 20 files with indirect coverage changes

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Test coverage of this pull request is below 90%

The unit tests run 51.63% of the lines this pull request
adds or changes (1015 of 1966 coverable lines).

The per-file breakdown, and the changed lines no test runs, are in the
job summary. Adding tests for those lines and pushing dismisses this
review automatically.

Lines that carry no executable code, and files the unit test targets do not
build, are not counted. If the new code genuinely cannot be unit tested, a
maintainer can dismiss this review.

The coordinator takes its dependencies (role, the other app, pacing,
push registration) from an injectable struct, the views that watch it
accept it as a parameter, and the role can be overridden by tests. The
new tests drive both sides of the transfer against each other,
including a restart and the erase round trip, plus the stores, the
errors, the suspended-connection guards and the remaining screens.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Test coverage of this pull request is below 90%

The unit tests run 86.57% of the lines this pull request
adds or changes (1714 of 1980 coverable lines).

The per-file breakdown, and the changed lines no test runs, are in the
job summary. Adding tests for those lines and pushing dismisses this
review automatically.

Lines that carry no executable code, and files the unit test targets do not
build, are not counted. If the new code genuinely cannot be unit tested, a
maintainer can dismiss this review.

@github-actions
github-actions Bot dismissed stale reviews from themself October 22, 2026 17:46

Patch coverage is now 90.95%, at or above the 90% threshold.

The announcement drops its "What this means" section and is titled
"Home Assistant has moved". The welcome notice explains the new App
Store listing, the overview's second list is "Set up again manually",
the open check asks "Did the old app open?", and the erased screen's
button reads "Open the new app".
Brings in the registration ownership from #6088. A transfer carries the
existing app's registration records, which name that app's vendor
identifier as their owner, so the Open Home Foundation app would treat
every transferred server as a restored device's registration, hold back
its reports and ask whether to replace the old device. After the import
the coordinator now takes those registrations over, keeping the same
mobile_app device; the reconnect stays with the push token adoption so
the new token is what reaches Home Assistant. The E2E vendor override is
left out of the transferred preferences, and the migration UI test's
build file gets an ID of its own after colliding with E2EFlow.swift.
…ion E2E

With location undecided and an HTTP-only server the app covers the
frontend with its location decision, also on a relaunch after
onboarding, so the sidebar underneath never opened. The driver now
closes that cover first and reaches Settings the way E2EFlow does.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants