Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .changeset/notifications-path-id-rename.md
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,17 @@ export const usePlaylistUpdates = <TResult = PlaylistUpdate[]>(
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<PlaylistUpdatesResponse>
}
).getPlaylistUpdates({
id: Id.parse(currentUserId),
userId: Id.parse(currentUserId)
})) as PlaylistUpdatesResponse | undefined

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ import {
} from '../models';

export interface GetNotificationsRequest {
userId: string;
id: string;
userId?: string;
timestamp?: number;
groupId?: string;
limit?: number;
types?: Array<GetNotificationsTypesEnum>;
}

export interface GetPlaylistUpdatesRequest {
userId: string;
id: string;
userId?: string;
}

/**
Expand All @@ -47,12 +49,16 @@ export class NotificationsApi extends runtime.BaseAPI {
* Get notifications for user ID
*/
async getNotificationsRaw(params: GetNotificationsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<NotificationsResponse>> {
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;
}
Expand All @@ -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,
Expand All @@ -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<runtime.ApiResponse<PlaylistUpdatesResponse>> {
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,
Expand Down
64 changes: 0 additions & 64 deletions packages/sdk/src/sdk/api/generated/default/apis/UsersApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>;
}
Expand Down Expand Up @@ -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<runtime.ApiResponse<Tracks>> {
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<Tracks> {
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.
Expand Down
Loading