Skip to content

Commit be0537f

Browse files
fix(cache-prime): personalize embedded users on three more endpoints (#14367)
## Summary Three more hooks were priming un-personalized users into the shared user cache — same bug class as the notifications fix in [#14366](#14366). API spec change merged in [AudiusProject/api#839](AudiusProject/api#839); this PR consumes it. | Hook | SDK call | Prime | | --- | --- | --- | | `useAllRemixContests` | `events.getRemixContests` | `primeRelatedData` | | `useUserRemixContests` | `users.getContestsByUser` | `primeRelatedData` | | `useNewAlbumReleases` | `playlists.getPlaylistsNewReleases` | `primeCollectionData` → `primeUserData` | In every case the backend handler already calls `app.getMyId(c)` to feed `MyID` into the `Parallel` query that hydrates embedded users — the query param just wasn't being sent because the SDK request type didn't expose it. With no value, `MyID = 0` and the SQL [short-circuited](https://github.com/AudiusProject/api/blob/main/api/dbv1/get_users.sql.go#L129-L136) `does_current_user_follow` to false for every embedded user. Clients then primed those into a shared cache that other surfaces read. ## Changes | File | Change | | --- | --- | | `packages/sdk/src/sdk/api/generated/default/apis/EventsApi.ts` | Add `userId?: string` to `GetRemixContestsRequest`; map to `queryParameters['user_id']`. | | `packages/sdk/src/sdk/api/generated/default/apis/UsersApi.ts` | Add `userId?: string` to `GetContestsByUserRequest`; map to `queryParameters['user_id']`. Path field is still `id` (the contest host); query `userId` is the requester. | | `packages/sdk/src/sdk/api/generated/default/apis/PlaylistsApi.ts` | Add `userId?: string` to `GetPlaylistsNewReleasesRequest`; map to `queryParameters['user_id']`. | | `packages/common/src/api/tan-query/events/useAllRemixContests.ts` | Pull `currentUserId` via `useCurrentUserId`; pass as `userId`. | | `packages/common/src/api/tan-query/events/useUserRemixContests.ts` | Same. Note this hook already took a `userId` prop for the contest host — that maps to the path `id`. `currentUserId` is separately threaded as the query. | | `packages/common/src/api/tan-query/collection/useNewAlbumReleases.ts` | Pull `currentUserId`; pass as `userId`. | | `.changeset/personalization-three-endpoints.md` | Minor `@audius/sdk` bump for the new optional fields. | ## Note on the SDK files in this diff I edited the generated `*.ts` files by hand here because `npm install` in my environment was blocked by a date-pinned registry constraint, which broke `node_modules` and stopped both `gen.js` and the rollup build from running. The edits are deterministic — they replicate the exact pattern openapi-generator already produces for analogous endpoints (e.g. `GetTrendingPlaylistsRequest` in the same `PlaylistsApi.ts`). A fresh `npm run gen` on a clean checkout should produce the same diff. Worth a quick visual confirmation during review. ## Test plan - [ ] CI green (typecheck/lint/tests). - [ ] On a fresh app load with a signed-in account: explore → contests carousel, an artist's contests tab, and browse → new albums all show correct Following state for surfaced artists without first having to navigate to each profile. - [ ] Network inspector on each of the three endpoints carries `?user_id=<hashed-current-user-id>` and `does_current_user_follow: true` for users actually followed in `related.users` / collection owners. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 6bd5c27 commit be0537f

7 files changed

Lines changed: 51 additions & 3 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@audius/sdk': minor
3+
---
4+
5+
Add an optional `userId?: string` query parameter to three endpoints so the backend can personalize embedded users in `related.users` / collection owners (`does_current_user_follow`, etc.):
6+
7+
- `events.getRemixContests`
8+
- `users.getContestsByUser`
9+
- `playlists.getPlaylistsNewReleases`
10+
11+
Without this, the endpoints' handlers (`app.getMyId(c)`) resolved the requester id from the missing `?user_id=` query and got `0`, so embedded user objects came back with `does_current_user_follow: false` for everyone. Clients that primed those into a shared cache (e.g. via `primeRelatedData` / `primeCollectionData`) silently poisoned follow state for the surfaced artists.
12+
13+
Existing callers continue to work unchanged — the field is optional. Pass `Id.parse(currentUserId)` (or whichever id your app treats as "me") to opt in.

packages/common/src/api/tan-query/collection/useNewAlbumReleases.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Id } from '@audius/sdk'
12
import { useQuery, useQueryClient } from '@tanstack/react-query'
23

34
import { userCollectionMetadataFromSDK } from '~/adapters/collection'
@@ -7,6 +8,7 @@ import { ID } from '~/models'
78

89
import { QUERY_KEYS } from '../queryKeys'
910
import { QueryKey, QueryOptions } from '../types'
11+
import { useCurrentUserId } from '../users/account/useCurrentUserId'
1012
import { entityCacheOptions } from '../utils/entityCacheOptions'
1113
import { primeCollectionData } from '../utils/primeCollectionData'
1214

@@ -28,14 +30,19 @@ export const useNewAlbumReleases = (
2830
const { limit = 10 } = args
2931
const { audiusSdk } = useQueryContext()
3032
const queryClient = useQueryClient()
33+
const { data: currentUserId } = useCurrentUserId()
3134

3235
const idQuery = useQuery({
3336
queryKey: getNewAlbumReleasesQueryKey({ limit }),
3437
queryFn: async (): Promise<ID[]> => {
3538
const sdk = await audiusSdk()
3639
const { data = [] } = await sdk.playlists.getPlaylistsNewReleases({
3740
limit,
38-
type: 'album'
41+
type: 'album',
42+
// Requester id so the backend personalizes embedded album-owner users
43+
// (e.g. does_current_user_follow). primeCollectionData fans these out
44+
// into the shared user cache, so without this they'd poison it.
45+
userId: currentUserId ? Id.parse(currentUserId) : undefined
3946
})
4047
const collections = transformAndCleanList(
4148
data,

packages/common/src/api/tan-query/events/useAllRemixContests.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
EventEntityTypeEnum,
33
EventEventTypeEnum,
44
GetRemixContestsStatusEnum,
5+
Id,
56
OptionalHashId,
67
Event as SDKEvent
78
} from '@audius/sdk'
@@ -16,6 +17,7 @@ import { removeNullable } from '~/utils'
1617

1718
import { QUERY_KEYS } from '../queryKeys'
1819
import { QueryKey, QueryOptions } from '../types'
20+
import { useCurrentUserId } from '../users/account/useCurrentUserId'
1921

2022
import { getEventIdsByEntityIdQueryKey, getEventQueryKey } from './utils'
2123

@@ -61,6 +63,7 @@ export const useAllRemixContests = (
6163
) => {
6264
const { audiusSdk } = useQueryContext()
6365
const queryClient = useQueryClient()
66+
const { data: currentUserId } = useCurrentUserId()
6467

6568
return useInfiniteQuery({
6669
queryKey: getAllRemixContestsQueryKey({ pageSize, status }),
@@ -74,7 +77,11 @@ export const useAllRemixContests = (
7477
const { data, related } = await sdk.events.getRemixContests({
7578
limit: pageSize,
7679
offset: pageParam,
77-
status
80+
status,
81+
// Requester id so the backend personalizes embedded related.users
82+
// (e.g. does_current_user_follow). Without it the cache primes those
83+
// users un-personalized and other surfaces read the bad state.
84+
userId: currentUserId ? Id.parse(currentUserId) : undefined
7885
})
7986

8087
// Prime related tracks + users (full objects, delivered alongside the

packages/common/src/api/tan-query/events/useUserRemixContests.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { removeNullable } from '~/utils'
1717

1818
import { QUERY_KEYS } from '../queryKeys'
1919
import { QueryKey, QueryOptions } from '../types'
20+
import { useCurrentUserId } from '../users/account/useCurrentUserId'
2021

2122
import { getEventIdsByEntityIdQueryKey, getEventQueryKey } from './utils'
2223

@@ -67,6 +68,7 @@ export const useUserRemixContests = (
6768
) => {
6869
const { audiusSdk } = useQueryContext()
6970
const queryClient = useQueryClient()
71+
const { data: currentUserId } = useCurrentUserId()
7072

7173
return useInfiniteQuery({
7274
queryKey: getUserRemixContestsQueryKey({ userId, pageSize, status }),
@@ -82,7 +84,11 @@ export const useUserRemixContests = (
8284
id: Id.parse(userId),
8385
limit: pageSize,
8486
offset: pageParam,
85-
status
87+
status,
88+
// Requester id so the backend personalizes embedded related.users
89+
// (e.g. does_current_user_follow). Path `id` is the contest host;
90+
// query `userId` is the current user viewing the page.
91+
userId: currentUserId ? Id.parse(currentUserId) : undefined
8692
})
8793

8894
// Prime related tracks + users (full objects, delivered alongside the

packages/sdk/src/sdk/api/generated/default/apis/EventsApi.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export interface GetRemixContestsRequest {
9797
offset?: number;
9898
limit?: number;
9999
status?: GetRemixContestsStatusEnum;
100+
userId?: string;
100101
}
101102

102103
export interface UnfollowEventRequest {
@@ -550,6 +551,10 @@ export class EventsApi extends runtime.BaseAPI {
550551
queryParameters['status'] = params.status;
551552
}
552553

554+
if (params.userId !== undefined) {
555+
queryParameters['user_id'] = params.userId;
556+
}
557+
553558
const headerParameters: runtime.HTTPHeaders = {};
554559

555560
if (!headerParameters["Authorization"] && this.configuration && this.configuration.accessToken) {

packages/sdk/src/sdk/api/generated/default/apis/PlaylistsApi.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export interface GetPlaylistsNewReleasesRequest {
9696
offset?: number;
9797
limit?: number;
9898
type?: GetPlaylistsNewReleasesTypeEnum;
99+
userId?: string;
99100
}
100101

101102
export interface GetTrendingPlaylistsRequest {
@@ -533,6 +534,10 @@ export class PlaylistsApi extends runtime.BaseAPI {
533534
queryParameters['type'] = params.type;
534535
}
535536

537+
if (params.userId !== undefined) {
538+
queryParameters['user_id'] = params.userId;
539+
}
540+
536541
const headerParameters: runtime.HTTPHeaders = {};
537542

538543
if (!headerParameters["Authorization"] && this.configuration && this.configuration.accessToken) {

packages/sdk/src/sdk/api/generated/default/apis/UsersApi.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ export interface GetContestsByUserRequest {
322322
offset?: number;
323323
limit?: number;
324324
status?: GetContestsByUserStatusEnum;
325+
userId?: string;
325326
}
326327

327328
export interface GetFollowersRequest {
@@ -1739,6 +1740,10 @@ export class UsersApi extends runtime.BaseAPI {
17391740
queryParameters['status'] = params.status;
17401741
}
17411742

1743+
if (params.userId !== undefined) {
1744+
queryParameters['user_id'] = params.userId;
1745+
}
1746+
17421747
const headerParameters: runtime.HTTPHeaders = {};
17431748

17441749
if (!headerParameters["Authorization"] && this.configuration && this.configuration.accessToken) {

0 commit comments

Comments
 (0)