feat(sdk)!: attribute audio uploads and previews to a required userId (no signatures) - #14555
Merged
Conversation
Audio uploads and preview generation now carry the id of the user they are made for — as plain metadata, not a signature. Validator nodes attest the resulting cids to that user on chain (OpenAudio/go-openaudio feat/content-auth-unsigned), which is what makes them claimable on a track once content authorization is enforced; generate_preview refuses users that do not already claim the source cid. No client-side signing is involved, deliberately. The id is an assertion; ownership is enforced where it always was, in the signed entity-manager write that names a cid on a track. That keeps every SDK flow working — including OAuth apps with no client-side wallet — with nothing but this parameter. BREAKING: userId is now required on tracks.uploadTrackFiles and uploads.createAudioUpload, and Storage.generatePreview requires a decoded userId. The high-level methods (createTrack, updateTrack, uploadTrack, publishTrack) already required userId and now thread it through. Required rather than optional so an integrator who upgrades cannot silently produce unclaimable uploads that fail later at publish; explicit rather than derived from auth state because a manager or developer-app session can act for more than one user. Clients updated to satisfy the requirement: useUpload passes the current account's id on track, stem, cover-art and collection-artwork uploads (with the id in every dependency array that reads it), the web stems saga passes the id it already looked up, and all four upload examples and their READMEs pass userId. Docs-site pages for the Uploads and Tracks APIs document the new parameter. Supersedes #14550, #14552 and #14554 (the EIP-712 signature approach). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 259c02b The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This was referenced Aug 8, 2026
rickyrombo
added a commit
that referenced
this pull request
Aug 8, 2026
#14556) Follow-up bug fix from the content-auth review of #14550/#14552 — independent of the redesign in #14555, works against today's servers. ## The bug `useUpdateTrack` never passes `generatePreview` to `sdk.tracks.updateTrack`, and the SDK's `updateTrack` only calls `generate_preview` when that flag is set. So editing a gated track's preview start point updates `preview_start_seconds` in the track metadata while the track keeps streaming the old `preview_cid`'s clip — the preview is never re-sliced at the new offset. As far as I can trace, nothing else regenerates it (`populateTrackMetadataWithUploadResponseV2` only touches `previewCid` when a new audio file was uploaded). ## The fix Pass `generatePreview: true` when the preview start is set and differs from the cached previous track's value: - The SDK already guards the rest: it skips regeneration when a new `audioFile` is present (transcoding produces the preview then) and when `previewStartSeconds` is undefined. - A cache miss for the previous track errs toward regenerating, which is idempotent for an unchanged offset. Once #14555 lands, this call site inherits the attributed `generate_preview` request automatically — `updateTrack` threads its `userId` internally. ## Testing `packages/common` typechecks clean; eslint clean on the touched file. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Marcus Pasell <marcus@audius.co> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 8, 2026
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 free
to 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.
Fresh implementation of upload/preview attribution on the unsigned design path. Supersedes #14550, #14552 and #14554 — the client-side EIP-712 signing approach — which can be closed in favor of this. Server counterpart: the unsigned-attribution stack OpenAudio/go-openaudio#477 → OpenAudio/go-openaudio#476 — a complete, linear alternative to the signed stack (OpenAudio/go-openaudio#459/#460); the two share only main.
Design
Audio uploads and
generate_previewcarry the id of the user they are made for — plain tus metadata / query parameter, no signature and no wallet client. The id is an assertion; what makes the scheme safe is unchanged from the analysis on the server PR:Dropping the signature is what keeps every SDK flow working — including OAuth apps with no client-side wallet — with nothing but this parameter. No proxy, no wallet plumbing, no timestamp windows.
BREAKING (major changeset included)
tracks.uploadTrackFilesrequiresuserId(encoded)uploads.createAudioUploadrequiresuserId(encoded)Storage.generatePreviewrequiresuserId(decoded) and sends it as a query paramHigh-level methods (
createTrack,updateTrack,uploadTrack,publishTrack) already requireduserIdand now thread it through — their callers need no changes. Required rather than optional so an upgraded integrator cannot silently produce unclaimable uploads that fail later at publish. Always explicit, never derived from auth state — a manager or developer-app session can act for more than one user (same convention asChatsApi.currentUserId).Client updates
useUpload: current account's id on track/stem/cover-art/collection-artwork uploads,requireUserId()guard so a missing account fails loudly at the call site, and the id is in every dependency array that reads itsdk/uploadsandsdk/trackspages document the parameter and why it existsTesting
Storage.test.tspins theuserIdquery param ongeneratePreview), typecheck clean🤖 Generated with Claude Code