Extract duplicated SimpleEventEmitter class from multiple service files into a shared utility file `js/utils/eventEmitter.js`.
- Created `js/utils/eventEmitter.js` with unified implementation.
- Refactored `AuthService`, `NostrService`, `ModerationService`, and `PlaybackService` to use the shared class.
- Added support for constructor-defined context strings for improved error logging.
- Added comprehensive unit tests for `SimpleEventEmitter`.
- Verified changes with targeted service tests.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Updated `NostrClient.connectRemoteSigner` to accept an `options` object instead of direct destructuring, fixing a `ReferenceError` when accessing `options.validator`.
- Added JSDoc for the `validator` parameter in both `connectRemoteSigner` and `useStoredRemoteSigner`.
- Removed outdated comments in `js/services/authProviders/nip46.js` that claimed `useStoredRemoteSigner` didn't support validators.
- Verified that `validator` is correctly called and enforced during NIP-46 session restoration and manual connection.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Implements a priority queue for NIP-07 (browser extension) requests to allow critical tasks (blocklist/prefs decryption) to jump the line.
- Updates NIP-46 client and adapters to support priority overrides for encryption/decryption.
- Updates UserBlockListManager, SubscriptionsManager, and HashtagPreferencesService to request HIGH priority when decrypting data.
- Ensures strict serialization for NIP-07 to prevent extension errors while optimizing latency for critical data.
Co-authored-by: PR0M3TH3AN <[email protected]>
Introduced a request queue in `js/nostr/nip07Permissions.js` to serialize all interactions with the NIP-07 extension (`window.nostr`).
Updated `js/userBlocks.js`, `js/services/hashtagPreferencesService.js`, and `js/auth/signingAdapter.js` to wrap direct extension calls with `runNip07WithRetry`, ensuring they participate in the queue.
This resolves "message channel closed" errors and timeouts caused by concurrent requests flooding the extension during sync operations.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Move NIP-07 extension login logic from `js/services/authProviders/nip07.js` to `NostrClient.loginWithExtension`.
- Add `validator` support to `NostrClient` login methods (`loginWithExtension`, `connectRemoteSigner`, `useStoredRemoteSigner`, `registerPrivateKeySigner`) to allow pre-session security checks.
- Update `nip07.js`, `nip46.js`, and `nsec.js` providers to inject `accessControl` checks via the new validator hook, ensuring consistent enforcement of whitelists/blacklists before activating the signer.
- This creates a unified "harness" for all signing methods within `NostrClient` while keeping business logic (access control) in the service layer.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Added `onMessage` callback to `NostrClient.listDirectMessages` to stream decrypted messages.
- Updated `NostrService.loadDirectMessages` to use the callback and trigger `applyDirectMessage` incrementally.
- Updated `ProfileModalController` to allow rendering updates during the initial load if the reason is `load-incremental`.
- Verified changes with existing tests and code review.
Co-authored-by: PR0M3TH3AN <[email protected]>
This commit updates `HashtagPreferencesService.decryptEvent` to register and utilize decryption methods from `window.nostr` (NIP-04 and NIP-44) as a fallback mechanism. This ensures that users without an active internal signer (e.g., read-only or extension-only users) can still decrypt their preferences if they have granted permission to the extension.
- Mirrors the decryption logic from `UserBlockListManager` (`js/userBlocks.js`).
- Adds logging for fallback attempts and failures.
- Preserves existing scheme selection logic (`determineDecryptionOrder`).
- Adds new test cases to `tests/hashtag-preferences.test.mjs` verifying fallback behavior when the active signer is missing or incapable.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Updated `NostrClient.fetchListIncrementally` to prioritize user's NIP-65 read relays, cap concurrent requests, and temporarily mark failing relays as unreachable.
- Added `markRelayUnreachable` to `NostrClient` for temporary relay exclusion.
- Updated `SubscriptionsManager`, `HashtagPreferencesService`, and `UserBlockListManager` to use `relayManager.getReadRelayUrls()` for selecting relays, ensuring consistency with user preferences.
- Added structured logging for relay selection in `fetchListIncrementally`.
- Updated unit tests to mock `relayManager` behavior correctly.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Reduced `fetchListIncrementally` timeout to 4000ms to fail faster on bad relays.
- Added 15s timeout to decryption calls in `HashtagPreferencesService`, `UserBlockListManager`, and `SubscriptionsManager` to prevent infinite hangs.
- Added handling for "message channel closed" error in `nip07Adapter` with a backoff delay to allow extension recovery.
- Prioritized preserving cached data on decryption failure instead of resetting to empty state.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Moved NIP-07 extension detection and permission logic from `NostrClient` to `nip07` provider.
- Removed redundant `login` method from `NostrClient`.
- Increased concurrency and added timeouts to `fetchListIncrementally` to prevent hanging on slow relays.
- Updated `UserBlocks` to force full fetch on cache miss, fixing "empty list" issues.
- Updated unit tests for login permissions and hashtag preferences to reflect architectural changes.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Wrapped NIP-07 adapter extension calls in `retryNip07Call` to handle transient failures and timeouts robustly.
- Updated `HashtagPreferencesService` to autosave changes to relays immediately on modification.
- Added race condition protection in `HashtagPreferencesService.load` to prevent overwriting optimistic local updates with stale relay data.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Update `fetchListIncrementally` in `js/nostr/client.js` to throw an error if all relays fail, preventing empty returns from being interpreted as data loss.
- Update `HashtagPreferencesService`, `UserBlockListManager`, and `SubscriptionsManager` to handle fetch errors gracefully without wiping local state.
- Update `js/nostr/nip07Permissions.js` to use a short timeout (3s) for experimental permission requests, fixing "clunky" login issues while preserving user interaction time for standard login.
- Remove `try/catch` in `adminListStore.js` fetch logic to allow error propagation to the fallback cache logic.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Updated `NostrClient.fetchListIncrementally` to accept a `since` override.
- Updated `HashtagPreferencesService.load` to pass `since` based on local cache timestamp.
- Ensures preferences are refreshed if local state is stale or missing, overriding potentially incorrect `SyncMetadataStore` state.
- Added regression tests for `fetchListIncrementally` since parameter logic.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Implemented optimistic UI updates for the channel subscribe button to improve responsiveness.
- Fixed a race condition in `js/subscriptions.js` and `js/services/hashtagPreferencesService.js` where lists were wiped on refresh due to `profileCache.activePubkey` not being initialized in time. Now using `profileCache.getProfileData(pubkey, ...)` to ensure the correct cache entry is loaded.
- Validated with targeted unit tests.
Co-authored-by: PR0M3TH3AN <[email protected]>
Removes a redundant `const normalizedInfoHash` declaration in `s3UploadService.js` that caused a `SyntaxError` and prevented the application from loading. The variable is already declared in the outer scope of the `try` block.
Introduces a race condition between the primary playback source (URL or Torrent) and a configurable timeout. If the primary source fails to reach the 'playing' state within the timeout window, the system automatically falls back to the alternative source.
- Adds `DEFAULT_PLAYBACK_START_TIMEOUT` to instance config (3000ms).
- Updates `PlaybackService` to implement timeout logic using `withTimeout` wrapper.
- Ensures proper cleanup of stalled attempts (resetting video element, destroying torrent client).
- Added `DEFAULT_PLAYBACK_SOURCE` to `config/instance-config.js` to allow choosing between "url" (default) and "torrent" priority.
- Updated `js/constants.js` to derive `URL_FIRST_ENABLED` flag from the configuration.
- Refactored `PlaybackService.execute()` in `js/services/playbackService.js` to robustly support "Torrent First" logic with fallback to URL, while maintaining "URL First" with fallback to Torrent.
- Added unit tests in `tests/services/playbackService_order.test.mjs` to verify playback order and fallback mechanics.
- Refactored `UploadModal.js` to trigger uploads immediately on file selection.
- Added progress bars and result fields (Video URL, Magnet, Torrent) to the UI.
- Fixed a crash in `r2Service.js` caused by `userLogger.debug` usage.
- Exposed `prepareUpload` and `uploadFile` methods in `r2Service` and `s3UploadService` for granular control.
- Updated `upload-modal.html` with new UI elements.
Previously, `StorageService.saveConnection` allowed multiple connections to be marked as `defaultForUploads: true` because it did not unset the flag on existing connections. This caused `loadFromStorage` (which uses `find`) to potentially pick up an old, invalid connection instead of the newly configured one, leading to a loop where the user is asked to configure credentials again.
This change modifies `saveConnection` to iterate through existing connections and unset `defaultForUploads` if the new connection is being saved as the default. This ensures the "default" invariant is maintained.
Added a unit test case to verify this behavior.