feat(invite): new endpoints and target users file and roles#11392
feat(invite): new endpoints and target users file and roles#11392imnaiyar wants to merge 5 commits intodiscordjs:mainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
📝 WalkthroughWalkthroughThis PR introduces target users management for Guild Invites. It adds new parameters to invite creation (roles, targetUsersFile), implements methods to fetch and update target users via FormData, retrieves job status for async user processing, and adds corresponding TypeScript definitions across multiple files. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant GuildInvite
participant GuildInviteManager
participant Discord API
Client->>GuildInvite: updateTargetUsers(targetUsersFile)
GuildInvite->>GuildInviteManager: updateTargetUsers(code, targetUsersFile)
GuildInviteManager->>GuildInviteManager: _createInviteFormData(targetUsersFile)
Note over GuildInviteManager: Resolve file/array to CSV<br/>Build FormData payload
GuildInviteManager->>Discord API: POST with FormData
Discord API-->>GuildInviteManager: Job queued
GuildInviteManager-->>GuildInvite: Promise<unknown>
GuildInvite-->>Client: Result
Client->>GuildInvite: fetchTargetUsersJobStatus()
GuildInvite->>GuildInviteManager: fetchTargetUsersJobStatus(code)
GuildInviteManager->>Discord API: GET job status
Discord API-->>GuildInviteManager: Status object
GuildInviteManager-->>Client: TargetUsersJobStatusForInvite
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In `@packages/discord.js/src/managers/GuildInviteManager.js`:
- Around line 266-313: The JSDoc return types are wrong for the async methods:
change fetchTargetUsers' `@returns` from {Buffer} to {Promise<Buffer>}, change
fetchTargetUsersJobStatus' `@returns` from {TargetUsersJobStatusForInvite[]}
(array) to {Promise<TargetUsersJobStatusForInvite>}, and ensure
updateTargetUsers (async) documents its return as {Promise<unknown>} if kept;
update the JSDoc comments above the functions fetchTargetUsers,
updateTargetUsers, and fetchTargetUsersJobStatus to reflect these Promise<>
return types.
- Around line 232-240: The current construction of options for invite creation
(in GuildInviteManager.js where options.role_ids is built from roles?.map(role
=> this.guild.roles.resolveId(role))) can include null entries which cause API
400s; update the logic that builds role_ids to either filter out falsy/null
resolved IDs (e.g., roles?.map(...).filter(Boolean)) or validate/throw if any
role fails to resolve so you never send nulls to the API, keeping references to
role_ids and this.guild.roles.resolveId in your change.
- Around line 322-334: In _createInviteFormData, filter out unresolved user IDs
returned by this.client.users.resolveId when handling an array targetUsersFile
so the CSV doesn't contain "null" entries; replace the current map(...).join
with a map -> filter(Boolean) -> join('\n') pipeline and if the resulting
usersCsv is empty either throw a clear error or handle it consistently (e.g.,
reject the request) before appending the Blob and payload_json to the FormData.
In `@packages/discord.js/src/structures/GuildInvite.js`:
- Around line 222-228: The JSDoc for the "Update target users of this invite"
method in GuildInvite.js has a typo in the `@returns` type — change
"Promes<unknown>" to "Promise<unknown>" in the JSDoc block above the
update-target-users method (the JSDoc attached to the GuildInvite update
function) so the return type is correctly documented.
- Around line 184-191: The roles Collection for GuildInvite is being constructed
with each Role instantiated from the whole invite payload (new Role(this.client,
data, this.guild)), causing mismatched fields; change the constructor to use the
individual role payload (use the loop variable, e.g., role) so each entry is new
Role(this.client, role, this.guild) and the Collection key remains consistent
with role.id in the roles assignment inside the GuildInvite class.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
packages/discord.js/src/managers/GuildInviteManager.jspackages/discord.js/src/structures/BaseGuildTextChannel.jspackages/discord.js/src/structures/GuildInvite.jspackages/discord.js/src/util/APITypes.jspackages/discord.js/typings/index.d.ts
🧰 Additional context used
🧬 Code graph analysis (1)
packages/discord.js/src/structures/GuildInvite.js (2)
packages/discord.js/src/managers/GuildInviteManager.js (7)
require(3-3)require(4-4)require(5-5)require(6-6)require(7-7)require(8-8)require(9-9)packages/discord.js/typings/index.d.ts (2)
Collection(1084-1084)Role(2965-3005)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Tests
🔇 Additional comments (8)
packages/discord.js/src/util/APITypes.js (1)
522-526: Doc addition looks good.
Clear external reference for the new enum.packages/discord.js/src/structures/BaseGuildTextChannel.js (1)
164-166: InviteCreateOptions docs are clear and consistent.
No issues found.packages/discord.js/src/structures/GuildInvite.js (2)
3-3: Required imports added for new roles support.Also applies to: 11-11
261-261: Serialization update is appropriate.packages/discord.js/typings/index.d.ts (2)
2064-2077: Type additions align with the new invite target-users API.The roles/targetUsersFile options, job-status type, and manager method signatures are coherent.
Also applies to: 4521-4543, 6605-6610
163-166: Verify thatdiscord-api-types0.38.36 exportsInviteTargetUsersJobStatus.The import is present in the typings file and the type is actively used (line 165, also used in a type definition with
status: InviteTargetUsersJobStatus). However, web searches did not confirm thatInviteTargetUsersJobStatusis available in discord-api-types v0.38.36. The package.json specifies^0.38.36, but the symbol's availability in this version could not be verified from available documentation or changelogs. Confirm the dependency version includes this export, or bump to the version that includes the required symbol.packages/discord.js/src/managers/GuildInviteManager.js (2)
3-8: Import updates look good.
107-117: Typedef shape is clear.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| const options = { | ||
| temporary, | ||
| max_age: maxAge, | ||
| max_uses: maxUses, | ||
| unique, | ||
| target_user_id: this.client.users.resolveId(targetUser), | ||
| target_application_id: targetApplication?.id ?? targetApplication?.applicationId ?? targetApplication, | ||
| role_ids: roles?.map(role => this.guild.roles.resolveId(role)), | ||
| target_type: targetType, |
There was a problem hiding this comment.
Avoid serializing unresolved role IDs.
roles?.map(...resolveId) can yield null, which becomes null entries in role_ids and can trigger 400s from the API. Filter (or fail fast) before POST.
Proposed fix (filter unresolved IDs)
- role_ids: roles?.map(role => this.guild.roles.resolveId(role)),
+ role_ids: roles
+ ?.map(role => this.guild.roles.resolveId(role))
+ .filter(Boolean),🤖 Prompt for AI Agents
In `@packages/discord.js/src/managers/GuildInviteManager.js` around lines 232 -
240, The current construction of options for invite creation (in
GuildInviteManager.js where options.role_ids is built from roles?.map(role =>
this.guild.roles.resolveId(role))) can include null entries which cause API
400s; update the logic that builds role_ids to either filter out falsy/null
resolved IDs (e.g., roles?.map(...).filter(Boolean)) or validate/throw if any
role fails to resolve so you never send nulls to the API, keeping references to
role_ids and this.guild.roles.resolveId in your change.
| async _createInviteFormData({ targetUsersFile, ...rest } = {}) { | ||
| const formData = new FormData(); | ||
| let usersCsv; | ||
| if (Array.isArray(targetUsersFile)) { | ||
| usersCsv = targetUsersFile.map(user => this.client.users.resolveId(user)).join('\n'); | ||
| } else { | ||
| const resolved = await resolveFile(targetUsersFile); | ||
| usersCsv = resolved.data.toString('utf8'); | ||
| } | ||
|
|
||
| formData.append('target_users_file', new Blob([usersCsv], { type: 'text/csv' }), 'users.csv'); | ||
| formData.append('payload_json', JSON.stringify(rest)); | ||
| return formData; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check Node engine requirement
echo "=== Node Engine Requirement ==="
rg -n "engines" packages/discord.js/package.json
echo -e "\n=== FormData/Blob usage in discord.js src ==="
rg -n "FormData\|Blob" packages/discord.js/src
echo -e "\n=== FormData/Blob imports ==="
rg -n "import.*FormData\|import.*Blob\|require.*FormData\|require.*Blob" packages/discord.js/src
echo -e "\n=== undici or polyfill usage ==="
rg -n "undici\|formdata" packages/discord.js/srcRepository: discordjs/discord.js
Length of output: 226
🏁 Script executed:
#!/bin/bash
# Locate and examine resolveId function
echo "=== Finding resolveId implementation ==="
rg -n "resolveId" packages/discord.js/src -A 5 -B 2 | head -100Repository: discordjs/discord.js
Length of output: 9356
🏁 Script executed:
#!/bin/bash
# Check package.json dependencies for any polyfills
echo "=== Checking for polyfill dependencies ==="
cat packages/discord.js/package.json | jq '.dependencies, .devDependencies' | grep -i "form\|blob\|fetch\|undici"Repository: discordjs/discord.js
Length of output: 248
🏁 Script executed:
#!/bin/bash
# Get the full engines object from package.json
echo "=== Full engines requirement ==="
cat packages/discord.js/package.json | jq '.engines'
echo -e "\n=== Check GuildInviteManager.js for imports ==="
head -50 packages/discord.js/src/managers/GuildInviteManager.jsRepository: discordjs/discord.js
Length of output: 1479
🏁 Script executed:
#!/bin/bash
# Find BaseManager to understand resolveId behavior
echo "=== BaseManager resolveId implementation ==="
rg -n "class BaseManager" packages/discord.js/src -A 50 | head -100
echo -e "\n=== resolveId implementation in BaseManager ==="
rg -n "resolveId.*{" packages/discord.js/src/managers/BaseManager.js -A 5Repository: discordjs/discord.js
Length of output: 1265
🏁 Script executed:
#!/bin/bash
# Get the full context of _createInviteFormData method
echo "=== Full _createInviteFormData method ==="
sed -n '322,334p' packages/discord.js/src/managers/GuildInviteManager.jsRepository: discordjs/discord.js
Length of output: 668
🏁 Script executed:
#!/bin/bash
# Find resolveId implementation in BaseManager or UserManager
echo "=== Find resolveId in BaseManager.js ==="
cat packages/discord.js/src/managers/BaseManager.js
echo -e "\n=== Find resolveId in UserManager.js ==="
rg -n "resolveId" packages/discord.js/src/managers/UserManager.js -A 8Repository: discordjs/discord.js
Length of output: 1807
🏁 Script executed:
#!/bin/bash
# Search for FormData usage to see how it's imported/used across the codebase
echo "=== FormData usage in GuildInviteManager and vicinity ==="
grep -n "FormData\|new Blob" packages/discord.js/src/managers/GuildInviteManager.js
echo -e "\n=== Check if there are any imports for FormData at top of file ==="
head -20 packages/discord.js/src/managers/GuildInviteManager.js | grep -i "form\|blob\|import\|require"Repository: discordjs/discord.js
Length of output: 1048
🏁 Script executed:
#!/bin/bash
# Get a better understanding of how resolveId behaves in UserManager
echo "=== UserManager resolve/resolveId methods ==="
rg -n "resolve\(" packages/discord.js/src/managers/UserManager.js -B 2 -A 8 | head -80Repository: discordjs/discord.js
Length of output: 558
🏁 Script executed:
#!/bin/bash
# Check CachedManager and parent classes for the actual resolveId implementation
echo "=== CachedManager.js ==="
cat packages/discord.js/src/managers/CachedManager.js
echo -e "\n=== Check parent class chain in managers ==="
head -30 packages/discord.js/src/managers/CachedManager.jsRepository: discordjs/discord.js
Length of output: 2474
🏁 Script executed:
#!/bin/bash
# See how resolveId is actually implemented in the full chain
rg -n "class.*Manager extends" packages/discord.js/src/managers/CachedManager.js
echo -e "\n=== Look for the actual resolveId implementation ==="
rg -n "resolveId" packages/discord.js/src/managers/CachedManager.js -B 2 -A 6Repository: discordjs/discord.js
Length of output: 162
🏁 Script executed:
#!/bin/bash
# Check DataManager.js for resolveId implementation
echo "=== DataManager.js ==="
cat packages/discord.js/src/managers/DataManager.jsRepository: discordjs/discord.js
Length of output: 1736
Filter out unresolved user IDs to prevent invalid entries in the CSV.
When resolveId returns null for unresolved users, the mapped array contains null values. Joining these with \n produces the string "null" in the CSV, which is not a valid user ID and can cause the API to reject or silently drop the request. Filter out falsy values to ensure only valid IDs are included.
FormData and Blob are available as stable globals in Node 22.12.0+ (the required minimum version), so no polyfill is needed.
Proposed fix
- usersCsv = targetUsersFile.map(user => this.client.users.resolveId(user)).join('\n');
+ const userIds = targetUsersFile
+ .map(user => this.client.users.resolveId(user))
+ .filter(Boolean);
+ usersCsv = userIds.join('\n');🤖 Prompt for AI Agents
In `@packages/discord.js/src/managers/GuildInviteManager.js` around lines 322 -
334, In _createInviteFormData, filter out unresolved user IDs returned by
this.client.users.resolveId when handling an array targetUsersFile so the CSV
doesn't contain "null" entries; replace the current map(...).join with a map ->
filter(Boolean) -> join('\n') pipeline and if the resulting usersCsv is empty
either throw a clear error or handle it consistently (e.g., reject the request)
before appending the Blob and payload_json to the FormData.
Depends on discordjs/discord-api-types#1493