importAccountRecord hard-required encryptedMasterKey, but a Blossom-only account is keyless (no encrypted payloads) and legitimately has none — so its synced record failed to import. Require the envelope ONLY when the record carries an encrypted connection that actually needs it to unlock.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
storageService now emits onConnectionsChanged (from importAccountRecord, the sync-import path); the upload modal subscribes and, when open + active user, re-derives its storage destination in place (re-attempt auto-unlock, recompute unlocked state, reload, repaint) — so credentials synced from Nostr are reflected without reopening. Bumped UploadModal's file-size baseline for the growth.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
fillStorageForm read the provider only from conn.provider (top-level), but getConnection returns { ...payload, meta } with the provider in meta (and no top-level provider for keyless Blossom) — so the selector always fell back to cloudflare_r2. Mirror connectionProvider()'s conn.provider || conn.meta?.provider fallback so the pane reflects the loaded default connection.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
The Storage pane saved every provider into a single shared "default" connection id,
so configuring Backblaze B2 overwrote your Cloudflare R2 (and vice-versa). The service
layer, upload path, and sync already supported a MAP of connections keyed by id
(listConnections / defaultForUploads / exportAccountRecord) — only the UI collapsed
them into one slot.
- Save each provider under its own slot keyed by provider id (cloudflare_r2 /
backblaze_b2 / generic_s3), preserving a single active defaultForUploads and lazily
migrating the legacy "default" slot to its provider id.
- Switching the provider dropdown now loads that provider's saved credentials (or
clears the fields for a fresh entry), so each provider keeps its own creds visibly.
- Sync is unchanged: it already exports the whole account record, so every provider's
connection syncs together.
Logic extracted to js/ui/profileModal/storageConnections.js (saveProviderConnection +
pure helpers) so ProfileStorageController stays under the 1000-line cap. Tests:
tests/storage-connections.test.mjs (7 — pure default/dup logic + integration proving
R2+B2 coexist with one default, the re-default switch, legacy-"default" migration, and
that the synced record carries both). Storage + profile-modal suites 69/69; lint clean.
Co-Authored-By: Claude Opus 4.8 <[email protected]>