Skip to content

feat: song listing and detail routes, legacy EVM auth flag, computed artist stream stats - #852

Merged
Akatenvictor merged 2 commits into
AudioBitsStellar:mainfrom
vjuliaife:feat/song-listing-legacy-evm-flag-artist-stats
Oct 18, 2026
Merged

Akatenvictor merged 2 commits into
AudioBitsStellar:mainfrom
vjuliaife:feat/song-listing-legacy-evm-flag-artist-stats

Conversation

@vjuliaife

Copy link
Copy Markdown
Contributor

Summary

  • GET /api/song/:id and GET /api/song are now routed, with visibility rules, explicit response shaping, filters and pagination. The unused SongService.createSong (and its unrouted controller handler) is removed.
  • The legacy EVM wallet-signature login and the Dynamic Labs wallet routes sit behind ENABLE_LEGACY_EVM_AUTH (default false) and return 410 Gone when it is off.
  • totalStreams, totalStreamTime and uniqueListeners are no longer client-settable or stored on users; profile responses compute them from song_play_events.

Changes

Song detail and listing (#810, #811)

  • SongRoutes.ts: GET / and GET /:id (both with optionalAuth), registered after /popular, /stream/:id and /embed/:id. /:id uses etagCache({ visibility: 'no-cache' }), so clients revalidate and get 304 when unchanged.
  • SongService.getSongView: validates the id as a UUID (400), returns 404 for flagged / non-ready songs unless the caller owns the song (owner also gets errorReason).
  • toSongView: explicit response shape (title, artist summary, cover, genre, duration, playCount, status, mintStatus, on-chain ids, createdAt). s3OriginalUrl, moderation and review fields are not returned. The same shape is used for list items.
  • ListSongsQueryDTO + SongService.listSongs: query-builder filters artistId, genreId, tag (slug), mintStatus, status (owner only, 403 otherwise), sort = newest|popular|title, page/limit (limit max 100). Public callers always get status = ready AND flagged = false. Response is { success, data, pagination } using the existing paginatedResponse util.
  • Removed SongService.createSong and SongController.createSong (not routed; mass-assigned arbitrary input).
  • docs/openapi.yaml: documented /api/song and /api/song/{id}.
  • Not done: the issue references a cursor pagination utility from Add cursor-based pagination utility #131; the repository only has the page/limit util (src/utils/pagination.ts), so that is what is used. No CacheService.getSong/cacheSong caching on the detail route, because that cache holds streaming manifests and the response differs for the owner. No index migration: EXPLAIN was not run (no database here); filter columns (artistId, genreId, status, mintStatus, createdAt) are already indexed, playCount and title sorts are not.

Legacy EVM auth flag (#809)

  • ENABLE_LEGACY_EVM_AUTH (default false), isLegacyEvmAuthEnabled() in authFlags.ts, and requireLegacyEvmAuth middleware that returns 410 with a hint to use Privy or email login.
  • Gated: GET /api/auth/nonce/:email, POST /api/auth/register, /register-listener, /login, POST /api/wallet/evm/create, /evm/signMessage.
  • ethers (in UserService) and the Dynamic wallet service (in WalletController) are now imported lazily. No other module under src/ imports ethers, @dynamic-labs-wallet/* or viem, so Stellar/Privy flows no longer load them at startup.
  • Documented in docs/PRIVY_MIGRATION_GUIDE.md (section 8.1, including the removal follow-up) and .env.example.
  • Inventory of EVM / Dynamic code paths:
    • Routes: src/routes/authRoutes.ts (nonce, register, register-listener, login), src/routes/walletRoutes.ts (/evm/create, /evm/signMessage).
    • Controllers: AuthController (getUserNonce, register, registerListener, login), WalletController (createEvmWallet, signMessage).
    • Services: UserService.createUser (uses ethers verifyMessage, validateEthereumAddress), AuthService.getNonce / login, src/services/Dynamic/WalletService.ts.
    • Config / utils: src/config/dynamic.ts, src/utils/dynamicUtils.ts (@dynamic-labs-wallet/node-evm, viem).
    • ABIs: src/abis/* (Diamond and facet ABIs; no imports from src/, only referenced by subgraph tests).
    • Env vars: DYNAMIC_ENVIRONMENT_ID, DYNAMIC_AUTH_TOKEN, LISK_SEPOLIA_RPC_URL.
  • Out of scope per the issue: deleting the code.

Artist stream stats (#807)

  • Option A: removed totalStreams, totalStreamTime, uniqueListeners from CreateUserDTO, UpdateUserDTO, the User entity, JWT payloads, AccountMergeService and docs/database-schema.md; migration 1757700000000-DropUserStreamStatColumns drops the columns (with a down).
  • SongStatsService.getArtistLifetimeTotals: counts plays, unique listeners and listening time (song duration per play) from song_play_events, cached in Redis for the existing 5 minute stats TTL under a key that the existing invalidateSong pattern already clears.
  • UserService own / public / updated profile responses now take these stats from that method.

Issues

Resolves #811
Resolves #810
Resolves #809
Resolves #807

Verification

Manual review of the full diff only. cargo build and cargo test were not run (TypeScript repository).

Run locally with npm ci --ignore-scripts:

  • npx jest --silent --forceExit on the new and affected test files: SongListing, SongControllerListing, SongRoutesOrder, ListSongsQueryDTO, legacyEvmGate, UserService.streamStats, SongStatsService, SongService, AuthService, authFlags all pass. The new tests cover each listing filter and sort, the visibility rules (flagged / processing / failed hidden from the public and shown to the owner), route ordering with /popular, the 410 gate with the flag unset, false and true, stripping of client-sent stream stats, and stats computed from play-event query results (with the database layer stubbed).
  • npx tsc --noEmit reports no errors in the files touched by this change.
  • Pre-existing failures, identical with and without this change: SongController.test.ts (13 failures; I only removed the createSong cases and pointed getSong at the new method), WalletController.test.ts, RoyaltyTemplateController.test.ts, uploadStreamingPipeline.test.ts, api.contract.test.ts.

Not verified: no database or Redis was available, so the migration, the SQL generated by the query builder and the EXPLAIN plans were not executed.

@drips-wave

drips-wave Bot commented Oct 18, 2026

Copy link
Copy Markdown

@vjuliaife Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Akatenvictor
Akatenvictor merged commit 6510a30 into AudioBitsStellar:main Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants