Improve Nostr sync failure messaging for offline mode

This commit is contained in:
thePR0M3TH3AN committed 2026-03-01 01:31:11 -05:00
1 parent 6cfd13e858
commit 7ec462a589
5 files changed
+57

No files matched your search

+12
View File
@@ -25,3 +25,15 @@
- Added `docs/nostr_namespace_reset.md` documenting menu options `8` (reset sync state) and `9` (start fresh namespace), plus validation steps for robust publish/restore.
- Linked the new guide from `docs/nostr_setup.md`, `docs/README.md`, and root `README.md`.
- Exposed the guide in website docs navigation via `landing/docs.html` (`Nostr Namespace Reset`).
## Nostr sync failure after namespace increment
- Root-cause pattern: when profile `offline_mode` is enabled, `sync_vault_async()` exits early and previously returned `None` without a helpful message, so UI showed only `❌ Sync failed…`.
- Fixes:
- `PasswordManager.sync_vault_async()` now sets `nostr_client.last_error` for early-return cases (`offline_mode`, missing encrypted index, and missing publish result).
- `main.handle_post_to_nostr()` now explicitly reports offline mode when no detailed error is present.
- Regression tests added:
- `src/tests/test_post_sync_messages.py::test_handle_post_failure_offline_mode_message`
- `src/tests/test_background_vault_sync_paths.py::test_sync_vault_async_sets_offline_error`
- Verified with local venv:
- `./.venv/bin/pytest -q src/tests/test_post_sync_messages.py`
- `./.venv/bin/pytest -q src/tests/test_background_vault_sync_paths.py`
+4
View File
@@ -431,6 +431,10 @@ def handle_post_to_nostr(
if detail:
print(colored(f"\N{CROSS MARK} Sync failed… {detail}", "red"))
logging.error("Failed to post encrypted index to Nostr: %s", detail)
elif getattr(password_manager, "offline_mode", False):
detail = "Offline mode is enabled. Disable it in Settings to sync."
print(colored(f"\N{CROSS MARK} Sync failed… {detail}", "red"))
logging.error("Failed to post encrypted index to Nostr: %s", detail)
else:
print(colored("\N{CROSS MARK} Sync failed…", "red"))
logging.error("Failed to post encrypted index to Nostr.")
+17
View File
@@ -3930,11 +3930,20 @@ class PasswordManager:
) -> dict[str, list[str] | str] | None:
"""Publish the current vault contents to Nostr and return event IDs."""
try:
client = getattr(self, "nostr_client", None)
if getattr(self, "offline_mode", False):
if client is not None and hasattr(client, "last_error"):
client.last_error = (
"Offline mode is enabled. Disable it in Settings to sync."
)
return None
encrypted = self.get_encrypted_data()
if not encrypted:
if client is not None and hasattr(client, "last_error"):
client.last_error = "No encrypted index data available to sync."
return None
if client is not None and hasattr(client, "last_error"):
client.last_error = None
pub_snap = getattr(self.nostr_client, "publish_snapshot", None)
manifest = None
event_id = None
@@ -3948,6 +3957,14 @@ class PasswordManager:
event_id = await self.nostr_client.publish_json_to_nostr(encrypted)
self.is_dirty = False
if event_id is None:
if (
client is not None
and hasattr(client, "last_error")
and not client.last_error
):
client.last_error = (
"Failed to publish encrypted index to configured relays."
)
return None
chunk_ids: list[str] = []
if manifest is not None:
@@ -1,4 +1,5 @@
import asyncio
from types import SimpleNamespace
from seedpass.core.manager import PasswordManager
from seedpass.core import manager as manager_module
@@ -56,3 +57,16 @@ def test_start_background_vault_sync_async_worker_path(monkeypatch):
assert ("sync_started",) in events
assert ("sync_finished", {"alt_summary": "async-path"}) in events
def test_sync_vault_async_sets_offline_error():
pm = PasswordManager.__new__(PasswordManager)
pm.offline_mode = True
pm.nostr_client = SimpleNamespace(last_error=None)
result = asyncio.run(pm.sync_vault_async())
assert result is None
assert pm.nostr_client.last_error == (
"Offline mode is enabled. Disable it in Settings to sync."
)
+10
View File
@@ -41,6 +41,16 @@ def test_handle_post_failure_shows_nostr_error(capsys):
assert "❌ Sync failed… Manifest out of date" in out
def test_handle_post_failure_offline_mode_message(capsys):
pm = SimpleNamespace(
sync_vault=lambda alt_summary=None: None,
offline_mode=True,
)
main.handle_post_to_nostr(pm)
out = capsys.readouterr().out
assert "Offline mode is enabled. Disable it in Settings to sync." in out
def test_handle_post_prints_all_ids(capsys):
pm = SimpleNamespace(
sync_vault=lambda alt_summary=None: {