Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(PermissionOverwrites)!: cache-independent resolve #10528

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Renegade334
Copy link
Contributor

@Renegade334 Renegade334 commented Oct 1, 2024

Please describe the changes this PR makes and why it should be merged:

Resolves #10450.

The linked issue relates to the current cache-dependent behaviour of PermissionOverwrites.resolve(), specifically that passing identical parameters to .resolve() can conditionally pass or fail validation depending on the state of the cache.

This isn't ideal, and the function would be better placed resolving the target via .resolveId() in a cache-independent manner.

This approach doesn't allow for overwrite.type to be optional if overwrite.id is a Snowflake, since it would no longer attempt to seek the respective member/role object from the cache to identify it as one or the other. There are two options for how to handle this:

  1. always enforce overwrite.type as mandatory, even if overwrite.id is a member object or role object;
  2. keep overwrite.type as optional if overwrite.id is a member object or role object (current behaviour), but enforce it as mandatory if overwrite.id is a Snowflake.

This PR implements the latter approach. It validates overwrite.id and overwrite.type as GuildMemberResolvable|RoleResolvable and OverwriteType|undefined respectively, then:

  • if overwrite.id is a Snowflake, it sets the type of the result to overwrite.type, throwing an error if it's not defined;
  • if overwrite.id is a member/role object, it sets the type of the result to the OverwriteType corresponding to that object.
    • There's then the question of what to do if overwrite.type is provided, but doesn't match the type of overwrite.id. This changeset plumps for throwing a validation error if that occurs, since silently overruling the type provided to the function without warning the user could lead to some hard-to-debug quirks.

The same cache-dependent type behaviour is also present on PermissionOverwriteManager#upsert(), and the behaviour of PermissionOverwriteManager#edit() is also seemingly unnecessarily cache-dependent. Think these should also be updated, but will wait for feedback on the PR so far.

Status and versioning classification:

  • Code changes have been tested against the Discord API, or there are no code changes
  • I know how to update typings and have done so, or typings don't need updating
  • This PR includes breaking changes (methods removed or renamed, parameters moved or removed)

@Renegade334 Renegade334 requested a review from a team as a code owner October 1, 2024 22:49
Copy link

vercel bot commented Oct 1, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
discord-js ⬜️ Ignored (Inspect) Visit Preview Oct 1, 2024 10:49pm
discord-js-guide ⬜️ Ignored (Inspect) Visit Preview Oct 1, 2024 10:49pm

@Renegade334
Copy link
Contributor Author

Renegade334 commented Nov 13, 2024

If this approach is kosher, then just wanted to check the following:

  • PermissionOverwriteManager#create() and PermissionOverwriteManager#edit() have the same cache-dependent erroring if a snowflake is passed, via the logic here:
    async upsert(userOrRole, options, overwriteOptions = {}, existing) {
    let userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole);
    let { type, reason } = overwriteOptions;
    if (typeof type !== 'number') {
    userOrRole = this.channel.guild.roles.resolve(userOrRole) ?? this.client.users.resolve(userOrRole);
    if (!userOrRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role');
    type = userOrRole instanceof Role ? OverwriteType.Role : OverwriteType.Member;
    }

    Should this behaviour also be altered to mirror this change?
  • PermissionOverwriteManager#edit() uses the cache to generate the existing permission bitfields, which are used as a base onto which the changes are added:
    edit(userOrRole, options, overwriteOptions) {
    const existing = this.cache.get(
    this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole),
    );

    If a snowflake is passed here and there is a cache miss, then the "base" bitfields will end up being empty, and any permissions that aren't explicitly modified will be silently truncated on the target. Does this also need some cache failure logic? (May or may not be out of scope.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.

Type error with permissionOverwrites
5 participants