Compare commits

..

No commits in common. "1cafa029f0aad622754d6a79feec1cdb4b1cda53" and "78e2fb2945cc3e9976b2962baf34330d1dd51dc6" have entirely different histories.

12 changed files with 94 additions and 185 deletions

File diff suppressed because one or more lines are too long

View File

@ -88,32 +88,4 @@ await message.channel.sendSlash('718642000898818048', 'sauce', a)
await response.reply();
}
```
### Receive messages after bot has replied `{botname} is thinking...`
> [aiko-chan-ai/discord.js-selfbot-v13#1055 (comment)](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/issues/1055#issuecomment-1949653100)
![image](https://cdn.discordapp.com/attachments/820557032016969751/1208363574477590538/image.png?ex=65e30346&is=65d08e46&hm=72771d6aa0d23f817f5daf8d2f33906ff74200aace7787c3cd02d2e30e58f8d5&)
```js
const channel = client.channels.cache.get('id');
channel
.sendSlash('289066747443675143', 'osu', 'Accolibed')
.then(async (message) => {
if (message.flags.has('LOADING')) { // owo is thinking...
return new Promise((r, rej) => {
let t = setTimeout(() => rej('timeout'), 15 * 60 * 1000); // 15m (DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE)
message.client.on('messageUpdate', (_, m) => {
if (_.id == message.id) {
clearTimeout(t);
r(m);
}
});
});
} else {
return Promise.resolve(message);
}
})
.then(console.log);
```

View File

@ -277,39 +277,6 @@ class Client extends BaseClient {
return ws.connect(this);
}
/**
* Logs the client in, establishing a WebSocket connection to Discord.
* @param {string} email The email associated with the account
* @param {string} password The password assicated with the account
* @param {string | number} [code = null] The mfa code if you have it enabled
* @returns {string | null} Token of the account used
*
* @example
* client.passLogin("test@gmail.com", "SuperSecretPa$$word", 1234)
*/
async passLogin(email, password, code = null) {
const initial = await this.api.auth.login.post({
auth: false,
versioned: true,
data: { gift_code_sku_id: null, login_source: null, undelete: false, login: email, password },
});
if ('token' in initial) {
return this.login(initial.token);
} else if ('ticket' in initial) {
const totp = await this.api.auth.mfa.totp.post({
auth: false,
versioned: true,
data: { gift_code_sku_id: null, login_source: null, code, ticket: initial.ticket },
});
if ('token' in totp) {
return this.login(totp.token);
}
}
return null;
}
/**
* Returns whether the client has logged in, indicative of being able to access
* properties such as `user` and `application`.

View File

@ -1,11 +1,11 @@
'use strict';
const EventEmitter = require('node:events');
const http = require('node:http');
const { setTimeout, setInterval, clearTimeout } = require('node:timers');
const WebSocket = require('../../WebSocket');
const { Status, Events, ShardEvents, Opcodes, WSEvents, WSCodes } = require('../../util/Constants');
const Intents = require('../../util/Intents');
const Util = require('../../util/Util');
const STATUS_KEYS = Object.keys(Status);
const CONNECTION_STATE = Object.keys(WebSocket.WebSocket);
@ -272,7 +272,7 @@ class WebSocketShard extends EventEmitter {
Version : ${client.options.ws.version}
Encoding : ${WebSocket.encoding}
Compression: ${zlib ? 'zlib-stream' : 'none'}
Agent : ${Util.verifyProxyAgent(client.options.ws.agent)}`,
Agent : ${client.options.ws.agent instanceof http.Agent}`,
);
this.status = this.status === Status.DISCONNECTED ? Status.RECONNECTING : Status.CONNECTING;
@ -283,7 +283,7 @@ class WebSocketShard extends EventEmitter {
// Adding a handshake timeout to just make sure no zombie connection appears.
const ws = (this.connection = WebSocket.create(gateway, wsQuery, {
handshakeTimeout: 30_000,
agent: Util.verifyProxyAgent(client.options.ws.agent) ? client.options.ws.agent : undefined,
agent: client.options.ws.agent instanceof http.Agent ? client.options.ws.agent : undefined,
}));
ws.onopen = this.onOpen.bind(this);
ws.onmessage = this.onMessage.bind(this);

View File

@ -85,23 +85,23 @@ class GuildForumThreadManager extends ThreadManager {
});
const attachmentsData = await Promise.all(requestPromises);
attachmentsData.sort((a, b) => parseInt(a.id) - parseInt(b.id));
data.attachments = attachmentsData;
if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild);
const post_data = await this.client.api.channels(this.channel.id).threads.post({
const data = await this.client.api.channels(this.channel.id).threads.post({
data: {
name,
auto_archive_duration: autoArchiveDuration,
rate_limit_per_user: rateLimitPerUser,
applied_tags: appliedTags,
message: body,
attachments: attachmentsData,
},
files: [],
reason,
});
return this.client.actions.ThreadCreate.handle(post_data).thread;
return this.client.actions.ThreadCreate.handle(data).thread;
}
}

View File

@ -1,6 +1,7 @@
'use strict';
const Buffer = require('node:buffer').Buffer;
const http = require('node:http');
const https = require('node:https');
const { setTimeout } = require('node:timers');
const makeFetchCookie = require('fetch-cookie');
@ -8,7 +9,6 @@ const FormData = require('form-data');
const fetchOriginal = require('node-fetch');
const { CookieJar } = require('tough-cookie');
const { ciphers } = require('../util/Constants');
const Util = require('../util/Util');
const cookieJar = new CookieJar();
const fetch = makeFetchCookie(fetchOriginal, cookieJar);
@ -40,17 +40,11 @@ class APIRequest {
make(captchaKey, captchaRqToken) {
if (!agent) {
if (Util.verifyProxyAgent(this.client.options.http.agent)) {
// Bad code
for (const [k, v] of Object.entries({
keepAlive: true,
honorCipherOrder: true,
minVersion: 'TLSv1.2',
ciphers: ciphers.join(':'),
})) {
this.client.options.http.agent.options[k] = v;
this.client.options.http.agent.httpsAgent.options.options[k] = v;
}
if (this.client.options.http.agent instanceof http.Agent) {
this.client.options.http.agent.options.keepAlive = true;
this.client.options.http.agent.options.honorCipherOrder = true;
this.client.options.http.agent.options.minVersion = 'TLSv1.2';
this.client.options.http.agent.options.ciphers = ciphers.join(':');
agent = this.client.options.http.agent;
} else {
agent = new https.Agent({

View File

@ -45,7 +45,7 @@ class ClientPresence extends Presence {
const data = {
activities: [],
afk: typeof afk === 'boolean' ? afk : false,
since: typeof since === 'number' && !Number.isNaN(since) ? since : 0,
since: typeof since === 'number' && !Number.isNaN(since) ? since : null,
status: status ?? this.status,
};
if (activities?.length) {

View File

@ -1076,10 +1076,10 @@ class Message extends Base {
* @returns {Promise<Message|Modal>}
*/
selectMenu(menu, values = []) {
let selectMenu = menu;
let selectMenu;
if (/[0-4]/.test(menu)) {
selectMenu = this.components[menu]?.components[0];
} else if (typeof menu == 'string') {
} else {
selectMenu = this.components
.flatMap(row => row.components)
.find(
@ -1092,7 +1092,7 @@ class Message extends Base {
if (values.length < selectMenu.minValues) {
throw new RangeError(`[SELECT_MENU_MIN_VALUES] The minimum number of values is ${selectMenu.minValues}`);
}
if (values.length > selectMenu?.maxValues) {
if (values.length > selectMenu.maxValues) {
throw new RangeError(`[SELECT_MENU_MAX_VALUES] The maximum number of values is ${selectMenu.maxValues}`);
}
values = values.map(value => {

View File

@ -404,10 +404,7 @@ class Activity {
}
toJSON(...props) {
return {
...Util.flatten(this, ...props),
type: typeof this.type === 'number' ? this.type : ActivityTypes[this.type],
};
return Util.flatten(this, ...props);
}
}
@ -695,6 +692,7 @@ class RichPresence extends Activity {
* Set the large image of this activity
* @param {?RichPresenceImage} image The large image asset's id
* @returns {RichPresence}
* @deprecated
*/
setAssetsLargeImage(image) {
this.assets.setLargeImage(image);
@ -705,6 +703,7 @@ class RichPresence extends Activity {
* Set the small image of this activity
* @param {?RichPresenceImage} image The small image asset's id
* @returns {RichPresence}
* @deprecated
*/
setAssetsSmallImage(image) {
this.assets.setSmallImage(image);
@ -715,6 +714,7 @@ class RichPresence extends Activity {
* Hover text for the large image
* @param {string} text Assets text
* @returns {RichPresence}
* @deprecated
*/
setAssetsLargeText(text) {
this.assets.setLargeText(text);
@ -725,6 +725,7 @@ class RichPresence extends Activity {
* Hover text for the small image
* @param {string} text Assets text
* @returns {RichPresence}
* @deprecated
*/
setAssetsSmallText(text) {
this.assets.setSmallText(text);
@ -878,16 +879,6 @@ class RichPresence extends Activity {
return this;
}
/**
* Secrets for rich presence joining and spectating (send-only)
* @param {?string} join Secrets for rich presence joining
* @returns {RichPresence}
*/
setJoinSecret(join) {
this.secrets.join = join;
return this;
}
/**
* Add a button to the rich presence
* @param {string} name The name of the button
@ -1066,13 +1057,6 @@ class SpotifyRPC extends RichPresence {
this.metadata.context_uri = `spotify:album:${id}`;
return this;
}
toJSON() {
return {
...super.toJSON({ id: false, emoji: false, platform: false, buttons: false }),
session_id: this.presence.client.sessionId,
};
}
}
exports.Presence = Presence;

View File

@ -188,7 +188,7 @@ class Options extends null {
referrer_current: '',
referring_domain_current: '',
release_channel: 'stable',
client_build_number: 267220,
client_build_number: 261141,
client_event_source: null,
},
compress: false,

View File

@ -1,6 +1,5 @@
'use strict';
const { Agent } = require('node:http');
const { parse } = require('node:path');
const process = require('node:process');
const { Collection } = require('@discordjs/collection');
@ -605,7 +604,7 @@ class Util extends null {
return user ? Util._removeMentions(`@${user.username}`) : input;
}
const member = channel.guild?.members.cache.get(id);
const member = channel.guild.members.cache.get(id);
if (member) {
return Util._removeMentions(`@${member.displayName}`);
} else {
@ -809,15 +808,6 @@ class Util extends null {
let defaultValue;
return () => (defaultValue ??= cb());
}
/**
* Hacking check object instanceof Proxy-agent
* @param {Object} object any
* @returns {boolean}
*/
static verifyProxyAgent(object) {
return typeof object == 'object' && object.httpAgent instanceof Agent && object.httpsAgent instanceof Agent;
}
}
module.exports = Util;

138
typings/index.d.ts vendored
View File

@ -176,9 +176,13 @@ export interface RichButton {
export class RichPresence extends Activity {
public constructor(client: Client, data?: object);
public metadata: RichPresenceMetadata;
/** @deprecated */
public setAssetsLargeImage(image?: string): this;
/** @deprecated */
public setAssetsLargeText(text?: string): this;
/** @deprecated */
public setAssetsSmallImage(image?: string): this;
/** @deprecated */
public setAssetsSmallText(text?: string): this;
public setName(name?: string): this;
public setURL(url?: string): this;
@ -191,7 +195,6 @@ export class RichPresence extends Activity {
public setEndTimestamp(timestamp: Date | number | null): this;
public setButtons(...button: RichButton[]): this;
public addButton(name: string, url: string): this;
public setJoinSecret(join?: string): this;
public static getExternal(
client: Client,
applicationId: Snowflake,
@ -770,7 +773,6 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
public fetchGuildWidget(guild: GuildResolvable): Promise<Widget>;
public sleep(timeout: number): Promise<void>;
public login(token?: string): Promise<string>;
public passLogin(email: string, password: string, code?: string | number): Promise<string | null>;
public QRLogin(): Promise<void>;
public logout(): Promise<void>;
public isReady(): this is Client<true>;
@ -1283,16 +1285,16 @@ export class GuildAuditLogs<T extends GuildAuditLogsResolvable = 'ALL'> {
export class GuildAuditLogsEntry<
TActionRaw extends GuildAuditLogsResolvable = 'ALL',
TAction = TActionRaw extends keyof GuildAuditLogsIds
? GuildAuditLogsIds[TActionRaw]
: TActionRaw extends null
? 'ALL'
: TActionRaw,
? GuildAuditLogsIds[TActionRaw]
: TActionRaw extends null
? 'ALL'
: TActionRaw,
TActionType extends GuildAuditLogsActionType = TAction extends keyof GuildAuditLogsTypes
? GuildAuditLogsTypes[TAction][1]
: 'ALL',
? GuildAuditLogsTypes[TAction][1]
: 'ALL',
TTargetType extends GuildAuditLogsTarget = TAction extends keyof GuildAuditLogsTypes
? GuildAuditLogsTypes[TAction][0]
: 'UNKNOWN',
? GuildAuditLogsTypes[TAction][0]
: 'UNKNOWN',
> {
private constructor(guild: Guild, data: RawGuildAuditLogEntryData, logs?: GuildAuditLogs);
public action: TAction;
@ -1549,7 +1551,7 @@ export class HTTPError extends Error {
}
// tslint:disable-next-line:no-empty-interface - Merge RateLimitData into RateLimitError to not have to type it again
export interface RateLimitError extends RateLimitData {}
export interface RateLimitError extends RateLimitData { }
export class RateLimitError extends Error {
private constructor(data: RateLimitData);
public name: 'RateLimitError';
@ -1893,8 +1895,8 @@ export class MessageActionRow<
T extends MessageActionRowComponent | ModalActionRowComponent = MessageActionRowComponent,
U = T extends ModalActionRowComponent ? ModalActionRowComponentResolvable : MessageActionRowComponentResolvable,
V = T extends ModalActionRowComponent
? APIActionRowComponent<APIModalActionRowComponent>
: APIActionRowComponent<APIMessageActionRowComponent>,
? APIActionRowComponent<APIModalActionRowComponent>
: APIActionRowComponent<APIMessageActionRowComponent>,
> extends BaseMessageComponent {
// tslint:disable-next-line:ban-ts-ignore
// @ts-ignore (TS:2344, Caused by TypeScript 4.8)
@ -3684,13 +3686,13 @@ export class ApplicationCommandPermissionsManager<
public remove(
options:
| (FetchSingleOptions & {
users: UserResolvable | UserResolvable[];
roles?: RoleResolvable | RoleResolvable[];
})
users: UserResolvable | UserResolvable[];
roles?: RoleResolvable | RoleResolvable[];
})
| (FetchSingleOptions & {
users?: UserResolvable | UserResolvable[];
roles: RoleResolvable | RoleResolvable[];
}),
users?: UserResolvable | UserResolvable[];
roles: RoleResolvable | RoleResolvable[];
}),
): Promise<ApplicationCommandPermissions[]>;
public set(
options: FetchSingleOptions & { permissions: ApplicationCommandPermissionData[] },
@ -4627,12 +4629,12 @@ export interface ApplicationCommandChannelOption extends BaseApplicationCommandO
export interface ApplicationCommandAutocompleteOption extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
type:
| 'STRING'
| 'NUMBER'
| 'INTEGER'
| ApplicationCommandOptionTypes.STRING
| ApplicationCommandOptionTypes.NUMBER
| ApplicationCommandOptionTypes.INTEGER;
| 'STRING'
| 'NUMBER'
| 'INTEGER'
| ApplicationCommandOptionTypes.STRING
| ApplicationCommandOptionTypes.NUMBER
| ApplicationCommandOptionTypes.INTEGER;
autocomplete: true;
}
@ -4904,9 +4906,9 @@ export interface AutoModerationRuleCreateOptions {
reason?: string;
}
export interface AutoModerationRuleEditOptions extends Partial<Omit<AutoModerationRuleCreateOptions, 'triggerType'>> {}
export interface AutoModerationRuleEditOptions extends Partial<Omit<AutoModerationRuleCreateOptions, 'triggerType'>> { }
export interface AutoModerationTriggerMetadataOptions extends Partial<AutoModerationTriggerMetadata> {}
export interface AutoModerationTriggerMetadataOptions extends Partial<AutoModerationTriggerMetadata> { }
export interface AutoModerationActionOptions {
type: AutoModerationActionType | AutoModerationActionTypes;
@ -5013,8 +5015,8 @@ export type CacheFactory = (
export type CacheWithLimitsOptions = {
[K in keyof Caches]?: Caches[K][0]['prototype'] extends DataManager<infer K, infer V, any>
? LimitedCollectionOptions<K, V> | number
: never;
? LimitedCollectionOptions<K, V> | number
: never;
};
export interface CategoryCreateChannelOptions {
permissionOverwrites?: OverwriteResolvable[] | Collection<Snowflake, OverwriteResolvable>;
@ -5367,12 +5369,12 @@ export interface ConstantsClientApplicationAssetTypes {
export type AutocompleteFocusedOption = Pick<CommandInteractionOption, 'name'> & {
focused: true;
type:
| 'STRING'
| 'INTEGER'
| 'NUMBER'
| ApplicationCommandOptionTypes.STRING
| ApplicationCommandOptionTypes.INTEGER
| ApplicationCommandOptionTypes.NUMBER;
| 'STRING'
| 'INTEGER'
| 'NUMBER'
| ApplicationCommandOptionTypes.STRING
| ApplicationCommandOptionTypes.INTEGER
| ApplicationCommandOptionTypes.NUMBER;
value: string;
};
@ -5931,20 +5933,20 @@ export interface GuildAuditLogsEntryExtraField {
MESSAGE_UNPIN: { channel: GuildTextBasedChannel | { id: Snowflake }; messageId: Snowflake };
MEMBER_DISCONNECT: { count: number };
CHANNEL_OVERWRITE_CREATE:
| Role
| GuildMember
| { id: Snowflake; name: string; type: OverwriteTypes.role }
| { id: Snowflake; type: OverwriteTypes.member };
| Role
| GuildMember
| { id: Snowflake; name: string; type: OverwriteTypes.role }
| { id: Snowflake; type: OverwriteTypes.member };
CHANNEL_OVERWRITE_UPDATE:
| Role
| GuildMember
| { id: Snowflake; name: string; type: OverwriteTypes.role }
| { id: Snowflake; type: OverwriteTypes.member };
| Role
| GuildMember
| { id: Snowflake; name: string; type: OverwriteTypes.role }
| { id: Snowflake; type: OverwriteTypes.member };
CHANNEL_OVERWRITE_DELETE:
| Role
| GuildMember
| { id: Snowflake; name: string; type: OverwriteTypes.role }
| { id: Snowflake; type: OverwriteTypes.member };
| Role
| GuildMember
| { id: Snowflake; name: string; type: OverwriteTypes.role }
| { id: Snowflake; type: OverwriteTypes.member };
STAGE_INSTANCE_CREATE: StageChannel | { id: Snowflake };
STAGE_INSTANCE_DELETE: StageChannel | { id: Snowflake };
STAGE_INSTANCE_UPDATE: StageChannel | { id: Snowflake };
@ -5975,8 +5977,8 @@ export interface GuildAuditLogsEntryTargetField<TActionType extends GuildAuditLo
INVITE: Invite;
MESSAGE: TActionType extends 'MESSAGE_BULK_DELETE' ? Guild | { id: Snowflake } : User;
INTEGRATION: Integration;
CHANNEL: NonThreadGuildBasedChannel | { id: Snowflake; [x: string]: unknown };
THREAD: ThreadChannel | { id: Snowflake; [x: string]: unknown };
CHANNEL: NonThreadGuildBasedChannel | { id: Snowflake;[x: string]: unknown };
THREAD: ThreadChannel | { id: Snowflake;[x: string]: unknown };
STAGE_INSTANCE: StageInstance;
STICKER: Sticker;
GUILD_SCHEDULED_EVENT: GuildScheduledEvent;
@ -6214,8 +6216,8 @@ export type GuildScheduledEventManagerFetchResult<
export type GuildScheduledEventManagerFetchSubscribersResult<T extends FetchGuildScheduledEventSubscribersOptions> =
T extends { withMember: true }
? Collection<Snowflake, GuildScheduledEventUser<true>>
: Collection<Snowflake, GuildScheduledEventUser<false>>;
? Collection<Snowflake, GuildScheduledEventUser<true>>
: Collection<Snowflake, GuildScheduledEventUser<false>>;
export type GuildScheduledEventPrivacyLevel = keyof typeof GuildScheduledEventPrivacyLevels;
@ -6402,8 +6404,8 @@ export type ModalActionRowComponentResolvable =
export interface MessageActionRowOptions<
T extends
| MessageActionRowComponentResolvable
| ModalActionRowComponentResolvable = MessageActionRowComponentResolvable,
| MessageActionRowComponentResolvable
| ModalActionRowComponentResolvable = MessageActionRowComponentResolvable,
> extends BaseMessageComponentOptions {
components: T[];
}
@ -6654,8 +6656,8 @@ export type MFALevel = keyof typeof MFALevels;
export interface ModalOptions {
components:
| MessageActionRow<ModalActionRowComponent>[]
| MessageActionRowOptions<ModalActionRowComponentResolvable>[];
| MessageActionRow<ModalActionRowComponent>[]
| MessageActionRowOptions<ModalActionRowComponentResolvable>[];
customId: string;
title: string;
}
@ -6818,19 +6820,19 @@ export type Partialize<
id: Snowflake;
partial: true;
} & {
[K in keyof Omit<T, 'client' | 'id' | 'partial' | E>]: K extends N ? null : K extends M ? T[K] | null : T[K];
};
[K in keyof Omit<T, 'client' | 'id' | 'partial' | E>]: K extends N ? null : K extends M ? T[K] | null : T[K];
};
export interface PartialDMChannel extends Partialize<DMChannel, null, null, 'lastMessageId'> {
lastMessageId: undefined;
}
export interface PartialGuildMember extends Partialize<GuildMember, 'joinedAt' | 'joinedTimestamp'> {}
export interface PartialGuildMember extends Partialize<GuildMember, 'joinedAt' | 'joinedTimestamp'> { }
export interface PartialMessage
extends Partialize<Message, 'type' | 'system' | 'pinned' | 'tts', 'content' | 'cleanContent' | 'author'> {}
extends Partialize<Message, 'type' | 'system' | 'pinned' | 'tts', 'content' | 'cleanContent' | 'author'> { }
export interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> {}
export interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> { }
export interface PartialOverwriteData {
id: Snowflake | number;
@ -6845,7 +6847,7 @@ export interface PartialRoleData extends RoleData {
export type PartialTypes = 'USER' | 'CHANNEL' | 'GUILD_MEMBER' | 'MESSAGE' | 'REACTION' | 'GUILD_SCHEDULED_EVENT';
export interface PartialUser extends Partialize<User, 'username' | 'tag' | 'discriminator'> {}
export interface PartialUser extends Partialize<User, 'username' | 'tag' | 'discriminator'> { }
export type PresenceStatusData = ClientPresenceStatus | 'invisible';
@ -7039,8 +7041,8 @@ export interface SweeperDefinitions {
export type SweeperOptions = {
[K in keyof SweeperDefinitions]?: SweeperDefinitions[K][2] extends true
? SweepOptions<SweeperDefinitions[K][0], SweeperDefinitions[K][1]> | LifetimeSweepOptions
: SweepOptions<SweeperDefinitions[K][0], SweeperDefinitions[K][1]>;
? SweepOptions<SweeperDefinitions[K][0], SweeperDefinitions[K][1]> | LifetimeSweepOptions
: SweepOptions<SweeperDefinitions[K][0], SweeperDefinitions[K][1]>;
};
export interface LimitedCollectionOptions<K, V> {
@ -7179,12 +7181,12 @@ export interface WebhookClientDataURL {
export type FriendRequestOptions =
| {
user: UserResolvable;
}
user: UserResolvable;
}
| {
username: string;
discriminator: number | null;
};
username: string;
discriminator: number | null;
};
export type WebhookClientOptions = Pick<
ClientOptions,