diff --git a/.changeset/notifications-path-id-rename.md b/.changeset/notifications-path-id-rename.md new file mode 100644 index 00000000000..877f8e70010 --- /dev/null +++ b/.changeset/notifications-path-id-rename.md @@ -0,0 +1,22 @@ +--- +'@audius/sdk': major +--- + +Rename the path field on `getNotifications` and `getPlaylistUpdates` from `userId` to `id`, matching the convention used by every `/users/{id}/…` method. Add an optional `userId` query field that carries the requester id for personalization of embedded `related.users` (e.g. `does_current_user_follow`). + +**Migration:** + +```ts +// Before +sdk.notifications.getNotifications({ userId: 'aE9MA' }) +sdk.notifications.getPlaylistUpdates({ userId: 'aE9MA' }) + +// After +sdk.notifications.getNotifications({ + id: 'aE9MA', // notifications owner (was `userId`) + userId: 'aE9MA' // requester id, for personalization of related.users +}) +sdk.notifications.getPlaylistUpdates({ id: 'aE9MA', userId: 'aE9MA' }) +``` + +The two ids differ only when a manager reads a managed user's notifications; in the normal flow they're the same value. The wire format and server URL are unchanged — only the request type shape was renamed to remove a collision between the path and the new query parameter. diff --git a/packages/common/src/api/tan-query/notifications/useNotificationUnreadCount.ts b/packages/common/src/api/tan-query/notifications/useNotificationUnreadCount.ts index 8dd6b3a2732..6a6905b0bce 100644 --- a/packages/common/src/api/tan-query/notifications/useNotificationUnreadCount.ts +++ b/packages/common/src/api/tan-query/notifications/useNotificationUnreadCount.ts @@ -35,14 +35,14 @@ export const useNotificationUnreadCount = () => { const response = await ( sdk.notifications as { getNotifications: (params: { - userId: string + id: string limit?: number }) => Promise<{ data?: { unreadCount?: number } }> } ).getNotifications({ - userId: Id.parse(currentUserId), + id: Id.parse(currentUserId), limit: 0 }) return response?.data?.unreadCount ?? 0 diff --git a/packages/common/src/api/tan-query/notifications/useNotifications.ts b/packages/common/src/api/tan-query/notifications/useNotifications.ts index 0b24c22e041..96782a04b85 100644 --- a/packages/common/src/api/tan-query/notifications/useNotifications.ts +++ b/packages/common/src/api/tan-query/notifications/useNotifications.ts @@ -76,6 +76,10 @@ export const useNotifications = (options?: QueryOptions) => { queryFn: async ({ pageParam = null }) => { const sdk = await audiusSdk() const response = await sdk.notifications.getNotifications({ + id: Id.parse(currentUserId), + // Requester id sent as `?user_id=` so the backend personalizes + // embedded related.users (e.g. does_current_user_follow). The path + // id alone identifies the notifications owner, not the requester. userId: Id.parse(currentUserId), limit: DEFAULT_LIMIT, timestamp: pageParam?.timestamp, diff --git a/packages/common/src/api/tan-query/playlist-updates/usePlaylistUpdates.ts b/packages/common/src/api/tan-query/playlist-updates/usePlaylistUpdates.ts index 6c66ab09fdd..6a090008574 100644 --- a/packages/common/src/api/tan-query/playlist-updates/usePlaylistUpdates.ts +++ b/packages/common/src/api/tan-query/playlist-updates/usePlaylistUpdates.ts @@ -38,13 +38,17 @@ export const usePlaylistUpdates = ( const sdk = await audiusSdk() // sdk.notifications.getPlaylistUpdates is not currently typed in the // public SDK surface; cast to the expected shape used in the legacy saga. + // userId carries the requester id as `?user_id=` so the backend can + // personalize related.users in the response. const response = (await ( sdk.notifications as { getPlaylistUpdates: (params: { - userId: string + id: string + userId?: string }) => Promise } ).getPlaylistUpdates({ + id: Id.parse(currentUserId), userId: Id.parse(currentUserId) })) as PlaylistUpdatesResponse | undefined diff --git a/packages/sdk/src/sdk/api/generated/default/apis/NotificationsApi.ts b/packages/sdk/src/sdk/api/generated/default/apis/NotificationsApi.ts index 01246270381..64d05ae27ad 100644 --- a/packages/sdk/src/sdk/api/generated/default/apis/NotificationsApi.ts +++ b/packages/sdk/src/sdk/api/generated/default/apis/NotificationsApi.ts @@ -26,7 +26,8 @@ import { } from '../models'; export interface GetNotificationsRequest { - userId: string; + id: string; + userId?: string; timestamp?: number; groupId?: string; limit?: number; @@ -34,7 +35,8 @@ export interface GetNotificationsRequest { } export interface GetPlaylistUpdatesRequest { - userId: string; + id: string; + userId?: string; } /** @@ -47,12 +49,16 @@ export class NotificationsApi extends runtime.BaseAPI { * Get notifications for user ID */ async getNotificationsRaw(params: GetNotificationsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { - if (params.userId === null || params.userId === undefined) { - throw new runtime.RequiredError('userId','Required parameter params.userId was null or undefined when calling getNotifications.'); + if (params.id === null || params.id === undefined) { + throw new runtime.RequiredError('id','Required parameter params.id was null or undefined when calling getNotifications.'); } const queryParameters: any = {}; + if (params.userId !== undefined) { + queryParameters['user_id'] = params.userId; + } + if (params.timestamp !== undefined) { queryParameters['timestamp'] = params.timestamp; } @@ -72,7 +78,7 @@ export class NotificationsApi extends runtime.BaseAPI { const headerParameters: runtime.HTTPHeaders = {}; const response = await this.request({ - path: `/notifications/{user_id}`.replace(`{${"user_id"}}`, encodeURIComponent(String(params.userId))), + path: `/notifications/{id}`.replace(`{${"id"}}`, encodeURIComponent(String(params.id))), method: 'GET', headers: headerParameters, query: queryParameters, @@ -94,16 +100,20 @@ export class NotificationsApi extends runtime.BaseAPI { * Get playlists the user has saved that have been updated for user ID */ async getPlaylistUpdatesRaw(params: GetPlaylistUpdatesRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { - if (params.userId === null || params.userId === undefined) { - throw new runtime.RequiredError('userId','Required parameter params.userId was null or undefined when calling getPlaylistUpdates.'); + if (params.id === null || params.id === undefined) { + throw new runtime.RequiredError('id','Required parameter params.id was null or undefined when calling getPlaylistUpdates.'); } const queryParameters: any = {}; + if (params.userId !== undefined) { + queryParameters['user_id'] = params.userId; + } + const headerParameters: runtime.HTTPHeaders = {}; const response = await this.request({ - path: `/notifications/{user_id}/playlist_updates`.replace(`{${"user_id"}}`, encodeURIComponent(String(params.userId))), + path: `/notifications/{id}/playlist_updates`.replace(`{${"id"}}`, encodeURIComponent(String(params.id))), method: 'GET', headers: headerParameters, query: queryParameters, diff --git a/packages/sdk/src/sdk/api/generated/default/apis/UsersApi.ts b/packages/sdk/src/sdk/api/generated/default/apis/UsersApi.ts index 3314b15d7e1..c2b8fb2e693 100644 --- a/packages/sdk/src/sdk/api/generated/default/apis/UsersApi.ts +++ b/packages/sdk/src/sdk/api/generated/default/apis/UsersApi.ts @@ -686,14 +686,6 @@ export interface GetUserFeedRequest { encodedDataSignature?: string; } -export interface GetUserForYouFeedRequest { - id: string; - limit?: number; - offset?: number; - maxPerArtist?: number; - userId?: string; -} - export interface GetUserIDsByAddressesRequest { address: Array; } @@ -4175,62 +4167,6 @@ export class UsersApi extends runtime.BaseAPI { return await response.value(); } - /** - * @hidden - * Returns a personalized For You feed for the user identified in the path. Twitter-style multi-source pipeline — candidate retrieval (in-network, trending, underground, similar-artist) → linear ranking (recency decay × engagement × social affinity, weighted by source) → diversity (per-artist cap + consecutive-same-artist lookahead). - * Get For You feed for user - */ - async getUserForYouFeedRaw(params: GetUserForYouFeedRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { - if (params.id === null || params.id === undefined) { - throw new runtime.RequiredError('id','Required parameter params.id was null or undefined when calling getUserForYouFeed.'); - } - - const queryParameters: any = {}; - - if (params.limit !== undefined) { - queryParameters['limit'] = params.limit; - } - - if (params.offset !== undefined) { - queryParameters['offset'] = params.offset; - } - - if (params.maxPerArtist !== undefined) { - queryParameters['max_per_artist'] = params.maxPerArtist; - } - - if (params.userId !== undefined) { - queryParameters['user_id'] = params.userId; - } - - const headerParameters: runtime.HTTPHeaders = {}; - - if (!headerParameters["Authorization"] && this.configuration && this.configuration.accessToken) { - const token = await this.configuration.accessToken("OAuth2", ["read"]); - if (token) { - headerParameters["Authorization"] = token; - } - } - - const response = await this.request({ - path: `/users/{id}/feed/for-you`.replace(`{${"id"}}`, encodeURIComponent(String(params.id))), - method: 'GET', - headers: headerParameters, - query: queryParameters, - }, initOverrides); - - return new runtime.JSONApiResponse(response, (jsonValue) => TracksFromJSON(jsonValue)); - } - - /** - * Returns a personalized For You feed for the user identified in the path. Twitter-style multi-source pipeline — candidate retrieval (in-network, trending, underground, similar-artist) → linear ranking (recency decay × engagement × social affinity, weighted by source) → diversity (per-artist cap + consecutive-same-artist lookahead). - * Get For You feed for user - */ - async getUserForYouFeed(params: GetUserForYouFeedRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { - const response = await this.getUserForYouFeedRaw(params, initOverrides); - return await response.value(); - } - /** * @hidden * Gets User IDs from any Ethereum wallet address or Solana account address associated with their Audius account.