- Replaced unbounded `Promise.all` with `pMap` and `RELAY_BACKGROUND_CONCURRENCY || 3` in `js/nostr/dmSignalEvents.js` and `js/services/dmNostrService.js` to prevent network saturation.
- Updated `scripts/check-hex.js` to exclude agent artifact directories (`perf/`, `test_logs/`, `context/`, etc.) to prevent lint failures when agents log code snippets or hex codes.
- Increased `maxBuffer` in `scripts/check-hex.js` to 10MB to be robust against large matches.
- Updated `js/services/exploreDataService.js` to trigger immediate data refresh (`refreshWatchHistoryTagCounts` and `refreshTagIdf`) when visibility state changes to visible, fixing a unit test failure.
- Includes daily performance report and context logs.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Replaced unbounded `Promise.all` with `pMap` and `RELAY_BACKGROUND_CONCURRENCY || 3` in `js/nostr/dmSignalEvents.js` and `js/services/dmNostrService.js` to prevent network saturation.
- Increased `maxBuffer` in `scripts/check-hex.js` to 10MB to prevent `ENOBUFS` when git text search matches large minified files in CI.
- Verified documentation in `content/docs/guides/upload-content.md` correctly specifies port 3000.
- Passed all unit and integration tests.
Co-authored-by: PR0M3TH3AN <[email protected]>
Replaces unbounded Promise.all with pMap and RELAY_BACKGROUND_CONCURRENCY (3) in js/nostr/dmSignalEvents.js and js/services/dmNostrService.js to prevent network saturation. Includes context logs and daily performance report.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Modifies `js/services/exploreDataService.js` to prevent starting background intervals if the document is hidden at initialization.
- Updates `scripts/check-hex.js` to increase max buffer size and exclude `js/webtorrent.min.js` to prevent `ENOBUFS` crashes.
- Adds `perf/hits-2026-02-17.json` inventory.
- Adds `daily-perf-report-2026-02-17.md` report.
- Adds `docs/agents/task-logs/daily/2026-02-17_06-45-57_perf-agent_completed.md`.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Added JSDoc to ModerationService class and methods.
- Added architectural overview in docs/moderationService-overview.md.
- Created task log.
Co-authored-by: PR0M3TH3AN <[email protected]>
The NIP-07 adapter uses type "nip07" but all permission pre-granting
checks only matched type "extension", causing NIP-07 browser extension
users to fail decryption for block/mute lists, subscriptions, DMs, and
watch history. Hashtag preferences appeared to work because their read
path had a separate fix, masking the systemic issue.
Changes:
- shouldRequestExtensionPermissions() now matches both "extension" and
"nip07" signer types (central fix affecting DM signals, comments,
publish helpers, and watch history fetch)
- buildDmDecryptContext() pre-grants extension permissions for NIP-07
- userBlocks.js: remove capabilities-gated decryptor check that failed
with lazy NIP-07 module injection (same fix already in subscriptions.js);
always resolve signer regardless of allowPermissionPrompt; increase
fast-path relay timeout from 6s to 10s
- watchHistoryService: recognize NIP-07 type and always resolve signer
- All publish paths (blocks, subscriptions, hashtags, relays, uploads,
sharing, moderation) now pre-grant permissions for NIP-07 signers
https://claude.ai/code/session_01PipsdaTQmw7wBTJ1LmJjkk
- Implements `toLightweightVideo` helper in `js/services/exploreDataService.js` to strip large fields (content, signatures, etc.) from video objects before sending to the worker.
- Updates `buildWatchHistoryTagCounts` and `buildTagIdf` to use lightweight objects.
- Adds `tests/services/exploreDataService.optimization.test.mjs` to verify correctness.
- Adds `benchmarks/worker_transfer_lightweight_bench.js` demonstrating ~40% improvement in transfer time.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Refactor `S3UploadService` to accept dependencies in constructor
- Move `resolveUploadIdentifier` to class method for mocking
- Add comprehensive unit tests for `S3UploadService` covering event emitter, validation, and upload logic
- Ensure `WebTorrent` dependency is mocked or polyfilled in test environment
Co-authored-by: PR0M3TH3AN <[email protected]>
- Introduce `js/constants.js` with semantic time constants (e.g., `ONE_MINUTE_MS`, `STANDARD_TIMEOUT_MS`) and feature-specific TTLs.
- Export `KIND_MUTE_LIST` from `js/nostrEventSchemas.js` to standardize NIP-51 mute list kind usage.
- Refactor `js/state/cache.js`, `js/nostr/cachePolicies.js`, `js/channelProfile.js`, and various services to use centralized constants instead of hardcoded magic numbers.
- Update `js/nostr/relayConstants.js` to derive values from the shared time constants.
- Replace duplicate definitions of timeouts and retry delays across the codebase.
Co-authored-by: PR0M3TH3AN <[email protected]>
Extracted complex logic from `AuthService.login` into private helper methods (`_validateAndNormalizeLoginInputs`, `_checkAccessControl`, `_updateGlobalState`, `_updateSavedProfiles`, `_initiatePostLogin`) to improve readability and maintainability.
Moved `SimpleEventEmitter` to `js/utils/simpleEventEmitter.js` and auth constants/normalization helpers to `js/services/authUtils.js` to reduce file size and coupling.
Co-authored-by: PR0M3TH3AN <[email protected]>
Extracted the complex playback logic from `js/app/playbackCoordinator.js` into a new `js/services/playbackStrategyService.js`.
This improves maintainability by separating the orchestration logic from the application glue code.
The coordinator now delegates to the service, passing a context object for UI interactions and state synchronization.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Remove redundant double signer readiness gate evaluation that added 5-10s
to the login path (authSessionCoordinator)
- Reduce decryption timeouts (10s→6s per scheme, 3s→1.5s retry delay,
8s→5s NIP-07 no-prompt, 45s→25s overall ensureLoaded) for faster scheme
fallback during list sync
- Fix storage tab unlock: remove overly strict capabilities check that
blocked lazy-injecting NIP-07 extensions, and add auto-unlock attempt
when profile modal opens with an active signer
- Fix subscription/hashtag decryption: always resolve signer for background
refreshes (was previously gated behind allowPermissionPrompt), and always
check window.nostr as fallback decryptor regardless of prompt mode
- Fix capabilities check in subscription decryption: use method existence
instead of dynamic capabilities getter that returns false during lazy
extension injection
- Wrap Promise.any decryptor calls in Promise.resolve().then() to catch
synchronous throws from NIP-07 adapter methods when extension modules
haven't loaded yet
- Make watch-history feed registration race-safe with pre-check and
try/catch for concurrent registration attempts
- Improve NIP-07 extension detection with DOMContentLoaded listener for
faster detection of extensions that inject during page load
https://claude.ai/code/session_0174XTB5ADJ9cMBSucqL9Wer
Extracts `fetchProfileFromRelay` helper method in `AuthService` to encapsulate timeout logic and event validation. This simplifies `loadOwnProfile` and makes it more readable and maintainable.
Also adds comprehensive tests for `loadOwnProfile` in `tests/auth-service.test.mjs`.
Co-authored-by: PR0M3TH3AN <[email protected]>
The NIP-07 login flow was extremely slow because list decryption (blocks,
subscriptions, hashtag preferences) started before the signer was ready.
On page refresh, all three services failed with "permission-required" and
scheduled 3-second retry delays, adding 6-10 seconds to every login.
Key fixes:
- List loading now waits for the permission pre-grant to complete before
attempting decryption, ensuring the signer is available on first try
- Extension wait timeout increased from 3s to 5s for slower extensions
- Decrypt timeouts reduced from 20s to 10s (signer is guaranteed ready)
- Auto-login now forwards authType/providerId from saved profiles
- Storage tab unlock falls back to ensureActiveSignerForPubkey when the
global signer is not yet registered
- Watch history feed registration adds defensive re-registration and
try/catch fallback to prevent "Feed not registered" errors
- Decryption scheme cache TTL extended from 10 minutes to 2 hours
- ensureExtensionPermissions waits for extension injection when there
are outstanding permissions to request (was returning immediately)
https://claude.ai/code/session_01T4wwPu7m5qp1Nxx3H2v57j
Moved logging helpers (`summarizeHexForLog`, `summarizeSecretForLog`, etc.) from `js/nostr/nip46Client.js` to `js/nostr/nip46LoggingUtils.js` to reduce clutter and improve reuse. Updated `js/nostr/client.js` and `js/services/authProviders/nip46.js` to import from the new module, removing duplicate definitions in the latter. Verified with existing tests.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Adds a default connection timeout of 5000ms to `RelayHealthService.checkRelay`.
- Adds comprehensive tests for `RelayHealthService` covering:
- Connection timeouts (mocked).
- Failure thresholds for user logging.
- Logging cooldowns (mocked time).
- Relay `disconnect` and `error` event handling.
- `nostrClient.markRelayUnreachable` integration.
- Refactors tests to use manual mocking for `setTimeout` and `Date.now` for stability.
Co-authored-by: PR0M3TH3AN <[email protected]>
Replaced the legacy "interests" string literal with NOTE_TYPES.HASHTAG_PREFERENCES
in profileCache calls to unify key usage. Updated migration logic and comments.
Verified that the underlying storage key remains consistent for backward compatibility.
Co-authored-by: PR0M3TH3AN <[email protected]>
Moves the repeatedly defined HEX64_REGEX constant to a shared utility
module to improve maintainability and consistency. Updates all consumers
to import from the new location.
Signed-off-by: Jules <[email protected]>
Co-authored-by: PR0M3TH3AN <[email protected]>
Three performance bottlenecks were causing slow list loading after NIP-07 login:
1. Each list service (blocks, subscriptions, hashtag preferences) maintained
its own isolated decryptionSuccessCache. When blocks decrypted with nip44_v2,
subscriptions and hashtag preferences had no way to know — they each had to
independently probe all schemes through the NIP-07 extension queue, tripling
the number of extension calls during the critical login path.
2. List loading was gated on both relaysReadyPromise AND permissionPromise in
the coordinator. Since the NIP-07 extension already grants decrypt permissions
during loginWithExtension(), the redundant pre-grant was adding 2-5 seconds
of unnecessary latency before any list fetching could begin.
3. The DECRYPT_RETRY_DELAY_MS was 10 seconds across all services. When a decrypt
attempt failed transiently (extension still initializing), the retry waited
far too long before trying again.
Changes:
- Create shared decryptionSchemeCache module used by all three list services
- Add fast-path: when shared cache knows the correct scheme, try ONLY that
scheme before falling back to parallel Promise.any() probe
- Remove permissionPromise from the list-loading gate in authSessionCoordinator
- Reduce DECRYPT_RETRY_DELAY_MS from 10s to 3s in all three services
- Clear shared cache on logout
https://claude.ai/code/session_013QrGMnxtMTsGTPqaP35jMj
When hashtag preferences decryption fails with "permission-required" during
background loading (allowPermissionPrompt=false), the service silently returned
without setting loaded state, scheduling a retry, or emitting a change event.
This left the UI stuck showing empty hashtag lists. The subscriptions module
already handled this case correctly.
Also fix error scheme mapping in Promise.any() catch blocks for both hashtag
preferences and subscriptions — the index into the original order array was
wrong after filtering out deduplicated scheme families.
https://claude.ai/code/session_016xYxLQ1U2XVVY5rFuCRKfc
Login with NIP-07 extensions was extremely slow because list loading
(blocks, subscriptions, hashtag preferences) happened sequentially and
each list's decryption tried encryption schemes one at a time.
Changes:
- Load blocks, subscriptions, and hashtags in parallel instead of
sequentially (blocks no longer blocks other lists from starting)
- Use Promise.any() to try all decryption schemes simultaneously
instead of trying nip44_v2 → nip44 → nip04 one-by-one
- Deduplicate same-family schemes (nip44/nip44_v2) to avoid redundant
extension calls
- Increase NIP-07 request queue concurrency from 3 to 5 to support
parallel decrypt operations during login
- Raise no-prompt decrypt timeout from 3s/5s to 8s since extensions
that have already granted permission still need time to decrypt
- Increase feed sync timeout from 8s to 12s to give lists more time
to settle before rendering unfiltered content
https://claude.ai/code/session_01V6m1gTecsppPrBHQnUyPnF
The user's block/mute list (NIP-51) was not being checked when
processing direct messages, allowing blocked users' messages to appear
in conversations, trigger notifications, and increment unseen counts.
This adds block filtering at four layers:
- nostrService.applyDirectMessage: drops incoming DMs from blocked users
before they enter the in-memory message cache
- nostrService.persistDirectMessageRecord: prevents blocked DM senders
from being persisted to IndexedDB or triggering notifications
- profileModalController.buildDmConversationData: filters blocked users
from the conversation list UI (catches pre-block persisted messages)
- applicationBootstrap: excludes blocked-user conversations from the
unread DM badge count
The block checker is injected via setDmBlockChecker() to keep
nostrService decoupled from userBlocks, wired up in app.js init().
https://claude.ai/code/session_01EAVLtAM14GN99Eik8otLg2
Increases NIP-07 concurrency to 3 and lowers priority for non-critical decryption tasks to prevent blocklist timeouts. Increases relay max listeners to 200 to mitigate warnings.
Co-authored-by: PR0M3TH3AN <[email protected]>
The login-to-feed pipeline had several issues causing lists (blocks,
subscriptions, hashtag preferences) to load too slowly or not reflect
in the feed:
1. All list loading was chained after profileStatePromise, adding
2.5-6s of unnecessary delay. Lists only need relay URLs, not profile
data. Now they chain off relaysReadyPromise instead, loading in
parallel with profile fetching.
2. The video grid refreshed immediately without waiting for any lists,
so the feed briefly displayed unfiltered content. Now the grid refresh
waits (up to 8s) for critical feed-filtering lists to settle.
3. Hashtag preferences weren't cached into the snapshot before the feed
rendered, so interests/disinterests were empty on first paint.
4. Subscription ensureLoaded had a 6s timeout that was too aggressive
for relay fetch (12s) + decryption (3-12s), causing silent failures.
Increased to 30s.
5. Subscription relay fetches for user and session actor ran sequentially.
Now they run in parallel via Promise.all.
https://claude.ai/code/session_01UKmTWb83AnQPRVQo3bKZqm
- Moved heavy tag counting and IDF calculation to `js/workers/exploreData.worker.js`.
- Extracted `collectVideoTags` to `js/utils/videoTags.js` (preserved original behavior).
- Extracted pointer normalization logic to `js/utils/pointerNormalization.js`.
- Refactored `js/services/exploreDataService.js` to use the worker.
- Added benchmark test `tests/benchmark-explore-data.spec.mjs`.
Measured Improvement:
- `buildTagIdf` execution time on main thread reduced from ~130ms blocking to ~0ms blocking (141ms total async time).
- Unblocks UI during periodic data refreshes.
Co-authored-by: PR0M3TH3AN <[email protected]>