Repository: discordjs/discord.js
File: packages/discord.js/src/structures/Message.js (JavaScript)

Code before:
   */
  get bulkDeletable() {
    return (
      (this.inGuild() &&
        Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
        this.deletable &&
        this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageMessages, false)) ??
      false
    );
  }

  /**
   * Whether the message is pinnable by the client user
   * @type {boolean}
   * @readonly
   */
  get pinnable() {
    if (this.system || !this.channel?.viewable) return false;

    const permissions = this.channel.permissionsFor(this.client.user);
    if (!permissions) return false;

    return (
      !this.guild ||
      permissions.has([PermissionFlagsBits.ReadMessageHistory, PermissionFlagsBits.PinMessages], false) ||
      (!this.guild.features.includes('PIN_PERMISSION_MIGRATION_COMPLETE') &&
        permissions.has([PermissionFlagsBits.ReadMessageHistory, PermissionFlagsBits.ManageMessages], false))
    );
  }

  /**
   * Fetches the Message this crosspost/reply/pin-add references, if available to the client
   * @returns {Promise<Message>}
   */
  async fetchReference() {
    if (!this.reference) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
    const { channelId, messageId } = this.reference;
    if (!messageId) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
    const channel = this.client.channels.resolve(channelId);
    if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
    const message = await channel.messages.fetch(messageId);
    return message;
  }

  /**
   * Whether the message is crosspostable by the client user
   * @type {boolean}
   * @readonly
   */
  get crosspostable() {
    const bitfield =

Review comment (bug):
As of 0ff239a602aed71c74c931c975c84900cf671312, we can use `GuildFeature.PinPermissionMigrationComplete`!

Code after:
   */
  get bulkDeletable() {
    return (
      (this.inGuild() &&
        Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
        this.deletable &&
        this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageMessages, false)) ??
      false
    );
  }

  /**
   * Whether the message is pinnable by the client user
   * @type {boolean}
   * @readonly
   */
  get pinnable() {
    const { channel } = this;

    if (this.system) return false;
    if (!this.guild) return true;
    if (!channel?.viewable) return false;

    const permissions = channel?.permissionsFor(this.client.user);
    if (!permissions) return false;

    return (
      permissions.has([PermissionFlagsBits.ReadMessageHistory, PermissionFlagsBits.PinMessages]) ||
      permissions.has([PermissionFlagsBits.ReadMessageHistory, PermissionFlagsBits.ManageMessages])
    );
  }

  /**
   * Fetches the Message this crosspost/reply/pin-add references, if available to the client
   * @returns {Promise<Message>}
   */
  async fetchReference() {
    if (!this.reference) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
    const { channelId, messageId } = this.reference;
    if (!messageId) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
    const channel = this.client.channels.resolve(channelId);
    if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
    const message = await channel.messages.fetch(messageId);
    return message;
  }

  /**
   * Whether the message is crosspostable by the client user
   * @type {boolean}
   * @readonly
   */