Skip to content

feat(media): graceful cloud fallback (Google Drive) on media server 5xx availability errors - #7028

Closed
ranjank2alpha wants to merge 54 commits into
block:mainfrom
ranjank2alpha:feat/media-server-5xx-gdrive-fallback
Closed

feat(media): graceful cloud fallback (Google Drive) on media server 5xx availability errors#7028
ranjank2alpha wants to merge 54 commits into
block:mainfrom
ranjank2alpha:feat/media-server-5xx-gdrive-fallback

Conversation

@ranjank2alpha

Copy link
Copy Markdown

Summary

When Blossom / NIP-96 / relay media servers experience outages, capacity limits, or internal failures (HTTP 500, 502, 503, 504), file attachments in chat fail completely, blocking collaboration until the backend recovers.

This PR introduces an intelligent, graceful fallback mechanism in
outedMediaUpload:

  • Detects HTTP 5xx availability errors (isRelayUnavailableError) during relay/blob media upload attempts while avoiding false triggers on client-side 4xx rejections.
  • If Google Drive is connected, seamlessly uploads the file to the user's Drive and shares the link as a native timeline attachment.
  • If not connected, surfaces a non-blocking toast with a direct action to connect external storage under Settings.

Key Changes

  • Error Classification: Pure isRelayUnavailableError detector classifying 500, 502, 503, 504 status codes and service unavailability messages.
  • **Graceful Divert in
    outedMediaUpload**: Intercepts 5xx failures on standard upload attempts and routes to Drive without dropping the user's message context.
  • Settings Navigation Event: openDriveSettingsEvent dispatches a clean UI navigation event to direct users to the connection setup when needed.
  • Unit Tests: Full suite of unit tests in driveUploadRouting.test.mjs verifying 5xx detection, 4xx exclusion, and fallback routing behavior.

Validation

  • TypeScript Typecheck: \pnpm exec tsc --noEmit\ passed (0 errors).
  • Unit Test Suite: \pnpm test\ passed 5,668 tests across 81 suites (0 failures).
  • Rust Backend: \cargo check\ clean in \desktop/src-tauri.

Ranjan and others added 30 commits August 7, 2026 14:25
Signed-off-by: Ranjan <ranjan@local.dev>
Signed-off-by: Ranjan <ranjan@local.dev>
…dows

Signed-off-by: Ranjan <ranjan@local.dev>
Signed-off-by: Ranjan <ranjan@local.dev>
…-sidecar build, align toolchain/pnpm/CMake with windows-canary.yml
Co-authored-by: Release Automation <release-automation@users.noreply.github.com>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
…OPVARIANT, CoTaskMemFree leak)

- PKEY_AppUserModel_ID now imported from Storage::EnhancedStorage (was wrongly under UI::Shell::PropertiesSystem, which only has PKEY_PIDSTR_MAX)
- Replace nonexistent InitPropVariantFromStringW with PROPVARIANT::from(&str) (the Win32 API of that name is header-only, never bound by windows-rs)
- Stop double-freeing PROPVARIANT via manual PropVariantClear now that it has its own Drop impl
- Free the SHGetKnownFolderPath COM buffer via CoTaskMemFree
- Fix Start Menu shortcut path assumption to match NSIS's actual subfolder default
….14-0

Fork was 9 versions / 141 upstream commits behind (last synced at merge-base f53bbd1, upstream now at desktop-v0.5.14). Brings in the fork's own additions on top:

- Windows WinRT toast notifications (+ this session's AUMID/shortcut-repair fixes)
- Message pinning, message forwarding, What's New splash
- File-preview and file-versioning system (pinned_messages.rs, FilesPanel, FileVersionPicker, channelFiles.ts, filePreview/*)
- Google Meet integration as a Huddle alternative

Notable merge decisions:
- Dropped the fork's standalone auto-updater wiring commit — upstream already ships its own updater.rs/use-updater.ts/tauri.conf.json updater plugin block; kept only our GitHub Releases endpoint config, which upstream leaves empty by design for downstream forks to fill in.
- events.rs build_message()/build_message_with_client_tags(): both sides independently added a new trailing parameter (upstream: link_preview_tags + sent_from_thread_tag + relay_base; fork: supersedes_ref_tags for file-versioning). Combined into one signature and updated every call site (messages.rs, huddle/pipeline.rs, egress_guard_tests.rs).
- SidebarSection.tsx muted+unread text color: took upstream's version (explicit full-color text when unread even while muted) over the fork's implicit-fallback version - directly relevant to the unread-visibility work planned this session.
- release.yml: kept the fork's own single-job Windows pipeline rather than adopting upstream's new multi-platform (macOS/Linux/Windows) pipeline, which hardcodes publishing to block/buzz's own repo and depends on sibling jobs (setup, release-macos-x64, release-linux) that don't exist here. Adopting upstream's real multi-platform release infra is a legitimate future project, not something to fold in silently as part of a version catch-up.
- Dropped four stray debug/scratch files (ANTIGRAVITY_VERIFY_PROMPT*.md, two empty _tmp_19_* files) that had been accidentally swept into a prior commit.
- Cargo.lock and pnpm-lock.yaml: took upstream's as the base rather than hand-splicing generated lockfiles; a real cargo build / pnpm install will fill in the fork-only dependencies (windows-winrt-notification, windows, mammoth, etc.) automatically.
Co-authored-by: Release Automation <release-automation@users.noreply.github.com>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Release Automation <release-automation@users.noreply.github.com>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Signed-off-by: ranjankai <ranjan@rkai.in>
…in the Files tab

Files over 5 MB, and all video and audio regardless of size, now upload to a 'Buzz uploads' folder in the sender's own Google Drive and post as a labelled link. Reuses the Meet OAuth connection on the narrow drive.file scope. Blocked with an explanation when Drive is not connected - no relay fallback.

Links shared in a channel are now first-class entries in its Files tab, named by the sender's markdown label, then Google surface, then path segment, then host. Version chains work across links and files in both directions, because the supersedes tag references an event rather than a file.

Drive uploads carry no imeta tag and always render as a link, so nothing fabricates a sha256 or points a video element at a Drive viewer page.

Extracts the 320-line generate_handler list from lib.rs into command_registry.rs as a macro, which the file-size ratchet required before two new commands could be registered.

Signed-off-by: ranjankai <ranjan@rkai.in>
Co-authored-by: Release Automation <release-automation@users.noreply.github.com>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
a and others added 24 commits August 22, 2026 13:38
Trial-merge audit plus five parallel reviews. Records a per-file conflict resolution table, the @channel catch-up regression upstream's Rust rewrite introduces, a fourth version location in Cargo.lock, and two Windows clippy fixes that must survive the merge.

Corrects four documents that described fork-only features - the Files tab, in-app preview, pinned messages, forwarding - as upstream's.

Signed-off-by: a <a@b>
Un-extracts command_registry.rs and takes upstream's inline generate_handler list, re-adding 11 fork commands. Upstream added 13 of its own in this release, and a lost registration fails only at runtime.

Re-applies supersedesTags and mentionScope onto sendChannelMessage, which upstream moved to tauriMessages.ts and whose argument positions it claimed. Adds a mention-scope clause to the new Rust unread catch-up so @channel stays urgent for people who were away - upstream's classifier has no knowledge of that tag.

Fixes four Windows-only clippy failures invisible to cargo check: two from this fork's ratchet extractions of upstream test modules, two from upstream test scaffolding that is dead code where only Unix builds it.

Signed-off-by: a <a@b>
PE, ELF and Mach-O binaries are rejected by the relay because it would then be serving them. They now go to the sender's Drive and post as a link instead of failing.

The routing list is deliberately NOT a copy of BLOCKED_FILE_MIME_TYPES: the relay reaches that list only after sniffing bytes with infer, which has no matcher for SVG, JavaScript, XHTML, .msi, .apk or .dmg - all of which upload fine today. Routing those would have broken a working flow for anyone without Drive connected.

Also stops google_access_token discarding the stored refresh token on transient network errors, which this change would otherwise trigger far more often, and clears the cached Drive folder id on disconnect.

Signed-off-by: a <a@b>
A local pnpm install rewrote the root package.json to 11.22.0 and it rode into 15c5783 via git add -u. pnpm/action-setup hard-errors on a mismatch with its own pinned version, failing the release build before anything compiles.

Adds a warning at the pin in release.yml, since the drift is silent and recurs on every pnpm install with a newer local pnpm.

Signed-off-by: a <a@b>
Windows toasts never appeared: tauri-winrt-notification's Toast::show() calls
WinRT with no COM apartment init, and Buzz posts from a bare std::thread with no
process MTA, so every call failed with CO_E_NOTINITIALIZED — swallowed by the
release build's missing console. Fix: hold a process-wide MTA on a dedicated
parked thread for the app lifetime; notification threads join it implicitly, so
toasts deliver and on_activated clicks still fire. Bump to 0.5.18-2.
…ettings visibility

Windows Settings > System > Notifications populates its "Get notifications
from these senders" list by enumerating subkeys under
HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\<aumid>.
Windows normally only creates that key after the first toast is posted,
meaning Buzz was omitted from Settings on clean installs until a notification
fired. Pre-create the subkey with ShowInActionCenter=1 and Enabled=1 during
startup registration so Buzz appears immediately in Settings upon launch.
Updates splash screen and docs (CONTEXT.md, FORK.md). Bump to 0.5.18-3.
Co-authored-by: Release Automation <release-automation@users.noreply.github.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
… thread-reply indexing

New Rust module channel_file_index.rs (SQLite store, migrations, writer,
query) with sync/list Tauri commands, plus client-side thread-reply file
indexing in channelFiles.ts. Phase 3 (point the Files tab at the index)
is not yet wired, so the two commands are registered but unused for now.

Also registers the TEMPORARY relay_debug_log diagnostic module (marked for
removal before release) in the same lib.rs invoke_handler block.
Surface @channel and @here as ranked composer autocomplete candidates
(scope-kinded through the mention types), rendered on top and inserted as
literals.
Remove canUseMentionScope, resolveMentionAudience, mentionScopeTag,
CHANNEL_MENTION_ADMIN_THRESHOLD and the now-orphaned PRIVILEGED_ROLES from
globalMentions.mjs, plus their .d.mts stubs and test blocks. These were an
earlier admin-threshold/audience design that the shipped autocomplete never
used; only their own unit tests referenced them. shouldNotifyForMentionScope,
detectMentionScope and mentionScopeOf remain (live callers).
…ad-state gating, multiplexed subscriptions

- Fire a desktop toast for every top-level message in an unmuted channel
  (muted channels excluded upstream); route top-level @-mentions through the
  same live path with mention-specific copy.
- Collapse per-channel live subscriptions into one multiplexed #h filter
  (chunked under the relay's per-filter cap) for both channel messages and
  mentions; buildChannelMentionFilter now accepts a channel-id array.
- Gate the Inbox unread filter on read-state readiness to stop stale flashes.
- Drop the unused buildChannelAuxFilter (dead code) alongside the filter work.

Carries TEMPORARY diagnostic logging (NOTIFY-DM, DM-EVENT, TOAST, NOTIFY-FEED,
REQ) kept in place while the DM-toast issue is still open; remove before release.
Merge desktop-v0.5.20 (76 upstream commits across 0.5.19+0.5.20) into the
fork. Resolved 22 conflicts, preserving fork features while adopting upstream
changes:

- send path: merged sendChannelMessage signature so upstream's rootEventId and
  the fork's supersedesTags + mentionScope all flow through (Rust command
  already accepts all three).
- messages.rs: kept upstream's new search_messages helpers alongside the fork's
  get_thread_replies doc.
- MentionAutocomplete: took upstream's refactor, re-applied the fork's @channel/
  @here scope suggestions (Megaphone icon, scope kind, description line).
- imetaMediaMarkdown: combined upstream's sha256 filter with the fork's external
  (Drive) exclusion; kept supersedesTags in the compose result.
- MessageActionBar: kept the fork's Forward button and upstream's toolbar Copy
  link (both surfaces).
- MessageTimeline: kept the fork's provider wrappers, adopted upstream's WebKit
  scroll-pill layout fix.
- ChannelScreen: took upstream's GuardedChannelPane + searchForwarding wrapper
  (fork props were a subset).
- SidebarSection: kept the fork's designed unread dot over upstream's inline
  count badge (fork renders the numeric badge elsewhere).
- release.yml: kept the fork's minimal Windows-only workflow.
- version reset to 0.5.20-0; temporary DM/relay debug scaffolding retained
  pending the open DM-toast fix.
0.5.20-0 is the bare upstream catch-up point (the desktop-v0.5.20 tag itself).
This build carries the fork stack on top of that base — WhatsApp-style channel/
mention toasts, the channel file index, mention autocomplete, and the rest of
the previously-uncommitted work — so it is the first fork build on 0.5.20: -1.
Downstream fixes from the conflict resolutions, verified by the full pipeline
(tsc 0 errors, 5664 tests pass, cargo check clean):

- messages.rs: drop the duplicate search_messages/build_search_messages_filter/
  search_messages_limit — upstream 0.5.20 relocated them into messages/search.rs,
  so the copies kept inline during merge were redundant; remove unused
  SearchResponse import.
- events.rs / events/message_tags.rs: reconcile module imports/re-exports
  (check_pubkey, imeta_tags, emoji_tags, mention_reference_tags, mention_scope_tag).
- ChannelScreen.tsx: add handleMessageMarkUnread/handleMessageMarkRead adapters
  bridging ChannelPane's TimelineMessage props to useChannelUnreadState; import
  TimelineMessage.
- useMentions.ts: scope handler calls setSelected(0) (correct local binding).
- MessageActionBar.tsx: drop orphaned quick-reaction helper refs.
- SidebarSection.tsx / CustomChannelSection.tsx: remove unused unreadCount prop
  (TS6133), since the fork renders the unread dot, not the inline count here.
…plex KIs

- Add the desktop-v0.5.20 catch-up entry (76 commits, 22 conflicts, green:
  tsc + 5664 tests + cargo), with the per-file resolution notes.
- Document the four desktop notification paths, the open DM-toast bug, and the
  exact temporary debug-scaffolding line map to strip before a clean release.
- Add the live-subscription multiplexing KI (root-cause fix for the REQ-storm
  that killed toasts/unread) so a future catch-up doesn't silently regress it.
- Bump the version-tracking pointer to 0.5.20.
…slot flag

The DM debug log showed 'REACHED onDmMessage' then 'BAIL dm-slot-off': the DM
desktop toast was gated on notificationSettings.slotAlertsEnabled.dm, a
per-category SOUND flag surfaced only under Settings > Notifications > Sound.
Channel and @mention toasts never checked it, so they fired while DMs (and
thread replies, same pattern) silently didn't whenever the corresponding sound
row was off. There is no per-category desktop-alert toggle in the UI, so users
could not fix this from settings.

Decouple delivery: the toast now fires whenever Desktop alerts is on and the
channel isn't muted (matching channels/mentions); slotAlertsEnabled.{dm,
thread_reply} now gates only the sound. Also removes this file's NOTIFY-DM
diagnostic scaffolding (its job is done).
The DM-toast root cause is found and fixed (sound-slot decoupling), so the
instrumentation is no longer needed. Removes as one unit:
- desktop/src-tauri/src/relay_debug_log.rs (deleted) + its mod/command
  registration in lib.rs
- the 3 TOAST append_line calls in commands/notifications.rs
- logDebug + the BUILD tag + REQ/EVENT/EOSE/CLOSED/AUTH/NOTICE frame loggers
  in relayClientSession.ts
- dmLog (DM-EVENT) in useLiveChannelUpdates.ts and the NOTIFY-FEED logger in
  use-feed-desktop-notifications.ts, plus their now-unused invoke imports
- the NOTIFY loggers in notifications/lib/desktop.ts (kept the real
  show_native_notification invoke + permission gate)

No behavioural change; real notification delivery paths untouched.
…ved; What's New 0.5.20-1

- Record the DM/thread toast fix and note it as upstream-worthy.
- Mark all debug scaffolding removed for the clean 0.5.20-1 release.
- Add the 0.5.20-1 What's New entry so the splash shows for this release.
The 1000-line cap forced brittle biome-ignore line-squashing on monolithic
hooks/components and fired on every upstream catch-up against upstream's own
growth (where extraction just re-conflicts next merge). allowedLineCount still
pins already-baseline-over files to their baseline, so this only widens the
ceiling for genuinely new growth. Clears the 6 files the 0.5.20 merge pushed
just past 1000 (max was 1096).
…5xx (0.5.20-2)

Motivated by a live BuilderLab Blossom/S3 503 outage. On a relay upload that
fails with a 5xx availability error (isRelayUnavailableError — not 4xx/network),
routedMediaUpload diverts that file to the sender's Google Drive:
- Drive connected: toast notice + Drive upload (link, not inline).
- Not connected: toast.error with a 'Connect Drive' action -> openDriveSettingsEvent
  -> AppShell goSettings('voice'), plus a clear thrown error.
Pure detector + 4 tests. Version 0.5.20-2, What's New entry, CONTEXT note.
@ranjank2alpha
ranjank2alpha requested a review from a team as a code owner August 29, 2026 08:28
@github-actions

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 00e61eafa917d296104006576b7a2ddbfd58bb5a...4739a353c47335e99cc1b3c816bd72cccbe19d2f.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 4739a353c47335e99cc1b3c816bd72cccbe19d2f to authorize a new review.
Any previous review applies only to its recorded range.

run: rustup target add "${{ matrix.target }}"

- name: Install Node
uses: actions/setup-node@v4
# windows-canary.yml sidesteps this the same way, with an explicit
# version pin instead.
- name: Install pnpm
uses: pnpm/action-setup@v4
shell: bash
run: cd desktop && pnpm tauri build --verbose --target "$TARGET" --bundles nsis --config src-tauri/tauri.release.conf.json
- name: Build and publish
uses: tauri-apps/tauri-action@v0
# windows-canary.yml sidesteps this the same way, with an explicit
# version pin instead.
- name: Install pnpm
uses: pnpm/action-setup@v4
shell: bash
run: cd desktop && pnpm tauri build --verbose --target "$TARGET" --bundles nsis --config src-tauri/tauri.release.conf.json
- name: Build and publish
uses: tauri-apps/tauri-action@v0
@ranjank2alpha

Copy link
Copy Markdown
Author

Closing this PR as this branch inadvertently carried cumulative fork history. Moving the discussion to a focused Feature Proposal / RFC to discuss the external storage fallback architecture first.

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.

5 participants