- Fix circular dependency in `js/adminListStore.js` by importing from `js/nostrClientRegistry.js`.
- Update `js/services/hashtagPreferencesService.js` to include legacy kind 30005 in filters.
- Fix JSDOM mocking in `tests/modal-accessibility.test.mjs` (navigator getter) and `UploadModal` selectors.
- Add `getRoot()` to `js/ui/components/UploadModal.js` for API consistency.
- Update `tests/magnet-utils.test.mjs` expectations to reflect removed default tracker.
- Mock `ensureActiveSignerForPubkey` in `tests/moderation/submit-report.test.mjs`.
- Fix mock loader path in `tests/moderation/trust-seeds.test.mjs` to target `trustBootstrap.js`.
- Fix duplicate pointer tags in `js/nostrEventSchemas.js`'s `buildCommentEvent`.
- Update `tests/nostr/comment-events.test.mjs` and `tests/comment-event-builder.test.mjs` to match current code behavior (legacy kinds, unique tags).
The `resolveSubscriptionsLink` method in `js/app.js` cached the sidebar DOM element (`this.subscriptionsLink`) during initialization. However, the sidebar is re-rendered dynamically, causing the cached reference to point to a detached DOM node. Consequently, `applyAuthenticatedUiState` would update the visibility of the detached element, leaving the visible sidebar unchanged.
This fix updates `resolveSubscriptionsLink` to check `this.subscriptionsLink.isConnected`. If the cached element is detached, it re-queries the DOM to retrieve the current live element, ensuring visibility updates apply correctly.
Additionally, `js/index.js` now awaits `applicationReadyPromise` before hydrating the sidebar, preventing race conditions during startup. `js/nostr/toolkit.js` was updated to support function-based subscription closers, fixing potential leaks.
- Updated `shimLegacySimplePoolMethods` in `js/nostr/toolkit.js` to correctly handle `nostr-tools` v2 subscription closers (which are functions) in `unsub`. This prevents subscription leaks that were causing relays to reject new requests, leading to empty subscription lists.
- Updated `bootstrapInterface` in `js/index.js` to await `applicationReadyPromise` before attempting to hydrate the sidebar navigation. This fixes a race condition where the sidebar "Subscriptions" link would remain hidden because the application auth state wasn't fully initialized when the sidebar was rendered.
Moves the moderation warning badge ("Content blocked...") to overlay the blurred thumbnail image instead of sitting below it or increasing card height. This logic is applied to both the main `VideoCard` and the `SimilarContentCard` to ensure layout consistency.
Changes:
- VideoCard.js: Refactor `updateModerationBadge` to append the badge container as a child of the `anchorEl` (thumbnail wrapper) with absolute positioning.
- SimilarContentCard.js: Implement `refreshModerationUi` logic to generate and overlay a simplified moderation badge on the thumbnail when `trustedMuted` context is present.
- Fix tests/moderation/video-card.test.mjs: Patch test environment to mock `globalThis.navigator`.
- Remove view count and separator from the metadata row in `SimilarContentCard.js`.
- Add new `buildEngagementSection` method to render view count and discussion count in a dedicated footer.
- Use Eye and Message SVG icons for engagement metrics.
- Ensure visual consistency with the main Video Card component.
- Fix import and definition of `SVG_NAMESPACE` to support icon creation.
- Moved view count and comments to a new bottom engagement section in `VideoCard.js`.
- Replaced text labels with Eye and Message SVG icons in `VideoCard.js`.
- Updated `video-modal.html` to include an Eye icon for the view count.
- Refactored `VideoModal.js` to update only the text node for view counts, preserving the icon.
- Removed "views" text suffix in favor of a cleaner numeric display.
- Moved view count from author metadata section to a new bottom "Engagement Section".
- Replaced "views" and "notes" text with SVG icons (Eye and Message Circle).
- Grouped views and comments side-by-side in the new section.
- Preserved existing data attributes for view/discussion counters.
- Cleaned up author metadata to only show Time and Edited status.
- Added `deleteObject` to `js/storage/r2-s3.js` for cleanup.
- Added `verifyPublicAccess` to `js/services/r2Service.js` to test bucket configuration.
- Refactored `components/upload-modal.html` to support wizard steps.
- Updated `js/ui/components/UploadModal.js` to manage wizard state and trigger verification.
- Exported `ensureBucketExists` from `js/storage/r2-s3.js` to resolve a module import error in `js/services/r2Service.js`.
- Verified the fix via code read.
- Confirmed syntax correctness of `r2-s3.js` modifications.
- Updated `R2Service` to attempt bucket creation via S3 API (`ensureBucketExists`) before upload. This improves the UX for users with Admin keys or custom domains while gracefully failing (with a warning) for users with minimal permissions.
- Modified `UploadModal` helper text to explicitly instruct users about enabling "Public Access" in the Cloudflare dashboard for new buckets.
- Updated `js/r2.js` to ensure the "Public Bucket URL" is always sanitized to include the `https://` protocol, fixing potential webseed generation issues.
- Removed requirement for Cloudflare API Token, Zone ID, and Worker Token from Upload Modal and R2Service.
- Simplified R2 configuration to require only Account ID, S3 Access Keys, and a user-provided Public Bucket URL.
- Added a read-only field in Upload Modal displaying the derived target bucket name (npub-based) for user reference.
- Implemented client-side torrent info hash calculation using `WebTorrent` (via `js/utils/torrentHash.js`) to generate magnet links before upload.
- Added a visual upload progress bar to the Upload Modal.
- Updated `js/r2.js` to ensure the Public Bucket URL always includes the `https://` protocol.
- Update `VideoCard.js` to display "• Edited" instead of "(edited)" for better visual consistency.
- Update `app.js` to format the modal's "Last Edited" timestamp as "Last edited: [Absolute] ([Relative])".
- Ensure `EditModal.js` correctly backfills and preserves `published_at` to prevent date resets.
- Verify edit logic with existing tests.
Prioritize `published_at` metadata over event `created_at` timestamp.
Backfill `published_at` during edit if missing to preserve original date.
Add "(edited)" label to video cards for modified content.
Display "Last Edited: [Date]" on video player modal.
Prioritize `published_at` metadata over event `created_at` timestamp.
Backfill `published_at` during edit if missing to preserve original date.
Add "(edited)" label to video cards for modified content.
Display "Last Edited: [Date]" on video player modal.
- Prioritize Kind 10000 events with `d=user-blocks` over plain mute lists in `loadBlocks`.
- Add `isTaggedBlockListEvent` helper for differentiation.
- Add regression test case to `tests/user-blocks.test.mjs` verifying that tagged lists override newer plain lists.
This commit modifies `js/userBlocks.js` to correctly parse Kind 10000 events that have empty content but populated `p` tags (used by clients like Primal). Previously, these events were treated as empty block lists, causing the user's block list to be cleared.
Changes:
- Refactored `loadBlocks` to check for empty content and fallback to extracting pubkeys from tags using `extractPubkeysFromTags`.
- Updated `loadBlocks` to use a sequential promise strategy (`Promise.any` then `Promise.allSettled`) to ensure eventual consistency without race conditions or double-processing.
- Added extensive tests in `tests/user-blocks.test.mjs` covering tag-only lists, whitespace content, and concurrency scenarios.
- Refactored `js/userBlocks.js` to merge Kind 10000 and Kind 30002 events on load, preventing overwritten mutes.
- Updated `js/constants.js` to set `DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD` to 4, enabling soft-hide (blur) behavior for lower mute counts.
- Update `ModerationService` to recognize session actors and load mutes from local storage.
- Update `UserBlockListManager` to persist blocks locally for session actors without relay publication.
- Ensure `submitReport` falls back to the session actor's signer.
- Add `resolveStorage` helper to safely access localStorage.
- Added `seedLocalBaseline` to `js/userBlocks.js` to merge admin blacklist into local block list for session actors.
- Implemented `_saveLocal` and `_loadLocal` in `js/userBlocks.js` to persist local-only block lists to `localStorage`.
- Updated `loadBlocks` to prioritize local storage for session actors, bypassing relay fetching when local data exists.
- Modified `js/app.js` to call `seedLocalBaseline` with the admin blacklist during initialization if the user is anonymous.
- Ensured `UserBlockListManager` correctly resolves `localStorage` in various environments (browser/test).
- Verified changes with `tests/user-blocks-local-seed.test.mjs`.
Updates `js/app.js` to:
1. Treat Trusted Seed mutes as hard blocks (`isAuthorBlocked` returns `true`) for anonymous users ("session actors"), ensuring strict filtering.
2. Refresh the entire video grid (`refreshAllVideoGrids`) instead of just the UI (`refreshVisibleModerationUi`) when `trusted-mutes` events arrive for anonymous users, ensuring blocked content is removed dynamically once the lists load. This fixes a race condition where content might render before the block list is fully fetched.
Subscribes `js/app.js` to `moderationService` events (`trusted-mutes`, `user-blocks`, `summary`). This ensures that asynchronous updates to trusted seed block lists (Kind 10000) trigger an immediate UI refresh, correctly applying moderation (blur/hide) even for anonymous session actors who rely on these seeds. Previously, the initial render would complete before the async lists arrived, leaving blocked content visible until a page reload.
- Fixed `ModerationService.reconcileTrustedMuteSubscriptions` to always force re-subscription to trusted seeds, bypassing previous state comparisons.
- Enhanced `ModerationService` to filter trusted seeds against the global admin blacklist.
- Added blacklist change event support to `AccessControl` and `TrustBootstrap` to dynamically update seeds when the blacklist changes.
- Added detailed logging to `ModerationService`, `TrustBootstrap`, and `AccessControl` to trace trust seed initialization and application.