Uh oh!
There was an error while loading. Please reload this page.
feat(for-you): switch useForYouFeed to dedicated /users/{id}/feed/for-you endpoint - #14388
Merged
Conversation
…-you endpoint The endpoint was re-introduced in AudiusProject/api#817 with a lean 3-source pipeline (in-network, trending, underground) + linear ranking + diversity pass. Previous implementation fell back to the generic recommended-tracks endpoint; this wires the hook to the purpose-built one. Changes: - Add GetUserFeedForYouRequest interface + getUserFeedForYou method to the generated UsersApi (mirrors the pattern of getUserRecommendedTracks) - Update useForYouFeed to call getUserFeedForYou, dropping the now-unused timeRange param Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Contributor
🌐 Web preview readyPreview URL:https://audius-web-preview-pr-14388.audius.workers.dev Unique preview for this PR (deployed from this branch). |
… hand-editing The prior commit on this branch hand-added getUserFeedForYou to the generated UsersApi.ts, which is the wrong layer — those files are produced by openapi-generator from the API repo's swagger spec. Manual edits get wiped on the next codegen run and the method name doesn't match the spec's operationId. This re-runs `node ./src/sdk/api/generator/gen.js --spec <swagger>` against the swagger from AudiusProject/api main (the for-you endpoint isn't in prod swagger yet, so --env prod can't be used until it deploys). The generated method is named `getUserForYouFeed` (from operationId "Get User For You Feed"), not `getUserFeedForYou` as the hand-edit assumed — hook updated to match. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
dylanjeffers added a commit
that referenced
this pull request
Jun 16, 2026
…ers -> .users)
authMiddleware backfills blockchainUserId/handle for users whose identity
row lacks them (the state of any guest / freshly signed-up user) by calling
the SDK. It used `req.app.get('audiusSdk').full.users.getUserAccount(...)`,
but the @audius/sdk instance has no `.full` namespace - `users` is a
top-level API. So `.full` is undefined and `.users` throws a synchronous
TypeError ("Cannot read properties of undefined (reading 'users')") on
EVERY new-user auth request (/users/update, /record_ip, etc).
Confirmed in prod logs:
TypeError: Cannot read properties of undefined (reading 'users')
at authMiddleware (build/src/authMiddleware.js:97:68)
msg: "Failed to update blockchainUserId/handle"
The bad accessor came in with the monorepo import (#14388) and only began
firing once #14474 (6/15) made loadAudiusSdk.cjs available so the SDK
actually initialized - matching the signup regression window. The
surrounding try/catch swallowed the error and called next(), so the
backfill silently never happened for new users.
Fix: use the correct accessor `audiusSdk.users.getUserAccount`. Also wrap
the now-live call in a 3s timeout (deferred into a promise so a
missing/misshapen sdk rejects instead of throwing synchronously), so that
once the call actually runs, a slow discovery lookup for a not-yet-indexed
new user degrades gracefully (logged, then next()) instead of stalling auth.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>dylanjeffers added a commit
that referenced
this pull request
Jun 16, 2026
…ers -> .users)
authMiddleware backfills blockchainUserId/handle for users whose identity
row lacks them (the state of any guest / freshly signed-up user) by calling
the SDK. It used `req.app.get('audiusSdk').full.users.getUserAccount(...)`,
but the @audius/sdk instance has no `.full` namespace - `users` is a
top-level API. So `.full` is undefined and `.users` throws a synchronous
TypeError ("Cannot read properties of undefined (reading 'users')") on
EVERY new-user auth request (/users/update, /record_ip, etc).
Confirmed in prod logs:
TypeError: Cannot read properties of undefined (reading 'users')
at authMiddleware (build/src/authMiddleware.js:97:68)
msg: "Failed to update blockchainUserId/handle"
The bad accessor came in with the monorepo import (#14388) and only began
firing once #14474 (6/15) made loadAudiusSdk.cjs available so the SDK
actually initialized - matching the signup regression window. The
surrounding try/catch swallowed the error and called next(), so the
backfill silently never happened for new users.
Fix: use the correct accessor `audiusSdk.users.getUserAccount`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>dylanjeffers added a commit
that referenced
this pull request
Jun 16, 2026
…ers -> .users) (#14482) ## Problem Users report failing/janky signups, with `POST https://identityservice.audius.co/users/update` misbehaving ([Slack thread](https://audius-internal.slack.com/archives/CA80RCL77/p1781637102823139)). `authMiddleware` (which gates `/users/update`, `/record_ip`, and every other authenticated endpoint) backfills `blockchainUserId`/`handle` for any identity `Users` row that lacks them — i.e. **every guest / freshly signed-up user**. It did this via: ```js req.app.get('audiusSdk').full.users.getUserAccount({ ... }) ``` But the `@audius/sdk` instance **has no `.full` namespace** — `users` is a top-level API (`audiusSdk.users.getUserAccount`). So `.full` is `undefined` and `.users` throws a **synchronous `TypeError`** on every new-user auth request. Confirmed in prod logs: ``` TypeError: Cannot read properties of undefined (reading 'users') at authMiddleware (build/src/authMiddleware.js:97:68) msg: "Failed to update blockchainUserId/handle" ``` The surrounding `try/catch` swallowed it and called `next()`, so the request proceeded but the **backfill silently never happened** — new identity rows never got `blockchainUserId`/`handle` set. ## Why it started now The bad accessor came in with the **monorepo import** of identity-service (#14388, 5/22), which rewrote `authMiddleware` to use `@audius/sdk`. It was dormant until #14474 (6/15) shipped `loadAudiusSdk.cjs` into the build, so the SDK actually initialized and this line began firing — matching the regression window. (identity hadn't been deployed in a while; 6/15 was the first monorepo image promoted to prod.) I verified prod is in the *benign* config otherwise: `environment=production` is set in `identity-service-secret`, so the SDK targets prod discovery — the issue is purely the wrong accessor, not SDK misconfig. ## Fix Use the correct accessor `audiusSdk.users.getUserAccount` in both `authMiddleware` and `parameterizedAuthMiddleware`. One-token change per call site. ## Notes - Ray's `record_ip` hunch is a red herring: `/users/update` doesn't call `recordIP`. (Though `/record_ip` is also gated by `authMiddleware`, so it hit the same TypeError — likely the source of the confusion.) - Same 6/15 batch also fixed a related latent crash: #14378 reads `src/data/disposable_email_blocklist.conf` at signup via an unguarded `fs.readFileSync`; that file wasn't copied into the build until #14474 (same one-liner that also added `loadAudiusSdk.cjs`). Worth hardening that read separately. - The batch's endpoint removals (#14458, #14472) are safe — the legacy `packages/libs` methods that hit them aren't called by any current client. ## Verification - Confirmed `getUserAccount` lives on the top-level `UsersApi` (`audiusSdk.users`) and there is no `.full` in the SDK instance shape (`@audius/sdk` `index.d.ts`). - Confirmed response shape `res.data.user` is still correct (`UserAccountResponse.data: Account`, `Account.user: User`). - Confirmed prod `environment=production`. After deploy, the `TypeError ... reading 'users'` log should disappear and `Failed to update blockchainUserId/handle` should drop to near-zero. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dylanjeffers added a commit
that referenced
this pull request
Jun 17, 2026
…k access (#14492) ## Problem Opening the comment drawer on a track screen crashes the app with a `TypeError` — **just by opening it, before any comment is sent**. This is separate from the post-comment crash fixed in #14490. ## Root cause The footer composer (`ComposerInput`) mounts on **every** comment-drawer open and computes `timestamps` in a render-phase `useMemo`: ```ts const { data: partialTrack } = useTrack(entityId, { select: (track) => pick(track, ['duration', 'genre', 'release_date', 'access']) }) ... const timestamps = useMemo(() => { if (!partialTrack || !partialTrack.access.stream) return [] // 💥 ... }, [partialTrack, value]) ``` `partialTrack` is a `pick(...)`, so it is **truthy even when the track has no `access` field**. `access` is typed as required on `Track`, but at runtime it is frequently absent — tracks hydrated from search, lineup, or notification caches before gated-access enrichment have no `access` yet. In that window `partialTrack.access.stream` dereferences `undefined` and throws, crashing the app the instant the drawer opens. Introduced in #14388 (`feat(for-you)`), which added this composer and the unguarded `partialTrack.access.stream` read. ## Fix Optional-chain the access read so it falls back to "no timestamps" when access info isn't loaded yet — the same outcome as the gated / no-stream-access path: ```ts if (!partialTrack || !partialTrack.access?.stream) return [] ``` This matches existing precedent in the codebase (e.g. `track?.access?.download` in `DownloadSection.tsx`). ## Testing - `eslint src/components/composer-input/ComposerInput.tsx` — passes - `tsc --noEmit` (`@audius/mobile`) — passes, 0 errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dylanjeffers added a commit
that referenced
this pull request
Aug 20, 2026
…der or unfurl (#14570) ## Problem Reported by Marcus: [audius.co/rehoxx/just-for-tonight-wmellark-hoonds](https://audius.co/rehoxx/just-for-tonight-wmellark-hoonds) still renders and plays, even though that artist's account is no longer active. The API already says it shouldn't. It returns `is_streamable: false` whenever a track is deleted or its owner is inactive. But the shared adapter listed the field in its **omit list** — introduced in #14388 under "Fields from API that are omitted in this model," simply because `TrackMetadata` didn't have the field, not for any deliberate reason. So the answer was computed by the API, sent over the wire, and deleted on arrival. `is_streamable` appeared exactly twice in the entire client codebase, and one of those was the line dropping it. With no signal, the track page rendered normally, played normally, and SSR served the track's title and artwork to crawlers and social unfurls. ## Change - Stop omitting `is_streamable`; add it to `TrackMetadata` as optional. - New `isTrackUnavailable` helper in common holds the semantics in one place. - Gate the track page on it across **web desktop, mobile web, and native mobile**. - SSR `+onRenderHtml` serves generic metadata, `noindex`, and no embed player when the flag is false. Two deliberate details: - The check is an explicit `=== false`. Not every track source populates the field, and an absent value must not read as unavailable. - Deleted tracks are excluded from the helper, so they keep their existing "deleted by artist" page. ## Copy `This Track Isn't Available` / `This track can no longer be streamed on Audius.` Deliberately says nothing about the account. The same flag covers an artist deactivating their own account *and* an account being suppressed by moderation, and we shouldn't tell users an artist deleted their account when that isn't what happened. ## Verification SSR output for the reported URL now returns `robots: noindex`, `og:title` "Track Unavailable • Audius", the default logo as `og:image`, and `twitter:card: summary` — no track title, artist name, or artwork. Desktop and mobile web checked against the live prod API; a normal trending track still renders fully. `tsc` and eslint clean across common/web/mobile.⚠️ The **native mobile** change is typecheck- and lint-verified only — it hasn't been run in a simulator. It mirrors the existing `ProfileScreen` deactivated branch structurally, but the layout is unproven. ## Related The API-side half is [AudiusProject/api#1023](AudiusProject/api#1023) — the stream endpoint didn't enforce `is_streamable` either, so the raw audio was reachable regardless of what the UI showed. ## Known gaps, not addressed here - An inactive artist's **profile** page still reads "This Account No Longer Exists / has been deleted" — same wrong-copy problem, keyed on `is_deactivated`. - Profile SSR still emits the artist's name, bio, and picture in og tags. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
getUserFeedForYoumethod to the generatedUsersApiSDK (mirrors the pattern ofgetUserRecommendedTracks— same request shape minustimeRange, sameTracksresponse type)useForYouFeedto call the new method, dropping the now-unusedtimeRangeparamrecommended-tracksendpoint; this wires the hook to the purpose-built pipeline introduced in feat(for-you): re-introduce /users/{id}/feed/for-you with lean 3-source pipeline api#817Test plan
currentUserIdis null)getUserRecommendedTracks)🤖 Generated with Claude Code