discord-sb.js 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/WebSocket.js +1 -1
- package/src/client/Client.js +55 -27
- package/src/managers/DeveloperManager.js +23 -12
- package/src/managers/QuestManager.js +29 -11
- package/src/managers/RelationshipManager.js +85 -32
- package/src/structures/ClientUser.js +41 -1
- package/src/structures/Guild.js +1 -1
- package/typings/enums.d.ts +100 -2
- package/typings/index.d.ts +15 -2
package/package.json
CHANGED
package/src/WebSocket.js
CHANGED
package/src/client/Client.js
CHANGED
|
@@ -457,6 +457,31 @@ class Client extends BaseClient {
|
|
|
457
457
|
return regions;
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
+
/**
|
|
461
|
+
* Requests a sync of guild data with Discord. Only works for user accounts.
|
|
462
|
+
* @param {Guild[]|Collection<Snowflake, Guild>} [guilds=this.guilds] Guilds to sync
|
|
463
|
+
* @returns {void}
|
|
464
|
+
*/
|
|
465
|
+
syncGuilds(guilds = this.guilds) {
|
|
466
|
+
if (this.user?.bot) return;
|
|
467
|
+
// Avoid rebuilding arrays if already mapped once
|
|
468
|
+
const ids = guilds instanceof Collection ? guilds.map((_, id) => id) : guilds.map(g => g.id);
|
|
469
|
+
this.ws.send({
|
|
470
|
+
op: 12,
|
|
471
|
+
d: ids,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Obtains a user from Discord, or the user cache if it's already available.
|
|
477
|
+
* @param {UserResolvable} user The user to fetch
|
|
478
|
+
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
|
479
|
+
* @returns {Promise<User>}
|
|
480
|
+
*/
|
|
481
|
+
fetchUser(user, options = {}) {
|
|
482
|
+
return this.users.fetch(user, options);
|
|
483
|
+
}
|
|
484
|
+
|
|
460
485
|
/**
|
|
461
486
|
* Obtains a sticker from Discord.
|
|
462
487
|
* @param {Snowflake} id The sticker's id
|
|
@@ -812,34 +837,37 @@ class Client extends BaseClient {
|
|
|
812
837
|
/**
|
|
813
838
|
* Install User Apps
|
|
814
839
|
* @param {Snowflake} applicationId Discord Application id
|
|
815
|
-
* @
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
840
|
+
* @param {string[]|string} [scopes=['applications.commands']] OAuth scopes to request when installing
|
|
841
|
+
* @returns {Promise<boolean>}
|
|
842
|
+
*/
|
|
843
|
+
async installUserApps(applicationId, scopes = ['applications.commands']) {
|
|
844
|
+
const scope = Array.isArray(scopes) ? scopes.join(' ') : scopes;
|
|
845
|
+
await this.api.oauth2.authorize.post({
|
|
846
|
+
query: {
|
|
847
|
+
client_id: applicationId,
|
|
848
|
+
scope,
|
|
849
|
+
},
|
|
850
|
+
data: {
|
|
851
|
+
permissions: '0',
|
|
852
|
+
authorize: true,
|
|
853
|
+
integration_type: 1,
|
|
854
|
+
dm_settings: {
|
|
855
|
+
allow_mobile_push: false,
|
|
823
856
|
},
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
});
|
|
839
|
-
} else {
|
|
840
|
-
return false;
|
|
841
|
-
}
|
|
842
|
-
});
|
|
857
|
+
},
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
return true;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Uninstall a previously authorized user application.
|
|
865
|
+
* @param {Snowflake} applicationId Discord Application id
|
|
866
|
+
* @returns {Promise<boolean>}
|
|
867
|
+
*/
|
|
868
|
+
async unInstallUserApp(applicationId) {
|
|
869
|
+
await this.api.oauth2.tokens(applicationId).delete();
|
|
870
|
+
return true;
|
|
843
871
|
}
|
|
844
872
|
|
|
845
873
|
/**
|
|
@@ -10,10 +10,6 @@ const DataResolver = require('../util/DataResolver');
|
|
|
10
10
|
* @extends {BaseManager}
|
|
11
11
|
*/
|
|
12
12
|
class DeveloperManager extends BaseManager {
|
|
13
|
-
constructor(client) {
|
|
14
|
-
super(client);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
13
|
/**
|
|
18
14
|
* Fetches all applications owned by the current user
|
|
19
15
|
* @param {boolean} [withTeamApplications=true] Whether to include team applications
|
|
@@ -81,15 +77,30 @@ class DeveloperManager extends BaseManager {
|
|
|
81
77
|
async edit(applicationId, data) {
|
|
82
78
|
const _data = {};
|
|
83
79
|
|
|
84
|
-
if (data.name)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (data.
|
|
88
|
-
|
|
89
|
-
|
|
80
|
+
if (data.name) {
|
|
81
|
+
_data.name = data.name;
|
|
82
|
+
}
|
|
83
|
+
if (data.description !== undefined) {
|
|
84
|
+
_data.description = data.description;
|
|
85
|
+
}
|
|
86
|
+
if (data.icon !== undefined) {
|
|
87
|
+
_data.icon = await DataResolver.resolveImage(data.icon);
|
|
88
|
+
}
|
|
89
|
+
if (data.tags) {
|
|
90
|
+
_data.tags = data.tags;
|
|
91
|
+
}
|
|
92
|
+
if (data.interactionsEndpointUrl !== undefined) {
|
|
93
|
+
_data.interactions_endpoint_url = data.interactionsEndpointUrl;
|
|
94
|
+
}
|
|
95
|
+
if (data.roleConnectionsVerificationUrl !== undefined) {
|
|
90
96
|
_data.role_connections_verification_url = data.roleConnectionsVerificationUrl;
|
|
91
|
-
|
|
92
|
-
if (data.
|
|
97
|
+
}
|
|
98
|
+
if (data.termsOfServiceUrl !== undefined) {
|
|
99
|
+
_data.terms_of_service_url = data.termsOfServiceUrl;
|
|
100
|
+
}
|
|
101
|
+
if (data.privacyPolicyUrl !== undefined) {
|
|
102
|
+
_data.privacy_policy_url = data.privacyPolicyUrl;
|
|
103
|
+
}
|
|
93
104
|
|
|
94
105
|
const result = await this.client.api.applications(applicationId).patch({ data: _data });
|
|
95
106
|
return new Application(this.client, result);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { setTimeout } = require('node:timers');
|
|
3
4
|
const { Collection } = require('@discordjs/collection');
|
|
4
5
|
const BaseManager = require('./BaseManager');
|
|
5
6
|
|
|
@@ -90,6 +91,14 @@ class QuestManager extends BaseManager {
|
|
|
90
91
|
return data;
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Refresh the quest cache from the API
|
|
96
|
+
* @returns {Promise<Object>} Latest quest data
|
|
97
|
+
*/
|
|
98
|
+
async refreshCache() {
|
|
99
|
+
return this.get();
|
|
100
|
+
}
|
|
101
|
+
|
|
93
102
|
/**
|
|
94
103
|
* Get user's orb balance (virtual currency)
|
|
95
104
|
* @returns {Promise<Object>} Balance data
|
|
@@ -197,19 +206,22 @@ class QuestManager extends BaseManager {
|
|
|
197
206
|
quest.updateUserStatus(data);
|
|
198
207
|
}
|
|
199
208
|
|
|
200
|
-
|
|
209
|
+
await this.refreshCache();
|
|
210
|
+
return this.getQuest(questId);
|
|
201
211
|
}
|
|
202
212
|
|
|
203
213
|
/**
|
|
204
214
|
* Update progress for a video quest
|
|
205
215
|
* @param {string} questId The quest ID
|
|
206
216
|
* @param {number} timestamp Current progress timestamp
|
|
217
|
+
* @param {boolean} [refresh=true] Whether to refresh the quest cache after the update
|
|
207
218
|
* @returns {Promise<Object>} Progress update result
|
|
208
219
|
*/
|
|
209
|
-
async videoProgress(questId, timestamp) {
|
|
220
|
+
async videoProgress(questId, timestamp, refresh = true) {
|
|
210
221
|
const data = await this.client.api.quests(questId)['video-progress'].post({
|
|
211
222
|
data: { timestamp },
|
|
212
223
|
});
|
|
224
|
+
if (refresh) await this.refreshCache();
|
|
213
225
|
return data;
|
|
214
226
|
}
|
|
215
227
|
|
|
@@ -218,15 +230,17 @@ class QuestManager extends BaseManager {
|
|
|
218
230
|
* @param {string} questId The quest ID
|
|
219
231
|
* @param {string} applicationId Application ID
|
|
220
232
|
* @param {boolean} [terminal=false] Whether this is a terminal heartbeat
|
|
233
|
+
* @param {boolean} [refresh=true] Whether to refresh the quest cache after the update
|
|
221
234
|
* @returns {Promise<Object>} Heartbeat result
|
|
222
235
|
*/
|
|
223
|
-
async heartbeat(questId, applicationId, terminal = false) {
|
|
236
|
+
async heartbeat(questId, applicationId, terminal = false, refresh = true) {
|
|
224
237
|
const data = await this.client.api.quests(questId).heartbeat.post({
|
|
225
238
|
data: {
|
|
226
239
|
application_id: applicationId,
|
|
227
240
|
terminal,
|
|
228
241
|
},
|
|
229
242
|
});
|
|
243
|
+
if (refresh) await this.refreshCache();
|
|
230
244
|
return data;
|
|
231
245
|
}
|
|
232
246
|
|
|
@@ -260,25 +274,28 @@ class QuestManager extends BaseManager {
|
|
|
260
274
|
'WATCH_VIDEO_ON_MOBILE',
|
|
261
275
|
].find(x => taskConfig.tasks?.[x] != null);
|
|
262
276
|
|
|
263
|
-
if (!taskName)
|
|
277
|
+
if (!taskName) {
|
|
278
|
+
console.log(`Unknown task type for quest "${questName}"`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
264
281
|
|
|
265
282
|
const secondsNeeded = taskConfig.tasks[taskName].target;
|
|
266
|
-
let secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0;
|
|
267
283
|
|
|
268
284
|
if (taskName === 'WATCH_VIDEO' || taskName === 'WATCH_VIDEO_ON_MOBILE') {
|
|
285
|
+
let secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0;
|
|
269
286
|
const maxFuture = 10;
|
|
270
287
|
const speed = 7;
|
|
271
288
|
const interval = 1;
|
|
272
289
|
const enrolledAt = new Date(quest.userStatus?.enrolled_at).getTime();
|
|
273
290
|
let completed = false;
|
|
274
291
|
|
|
275
|
-
while (
|
|
292
|
+
while (!completed && secondsDone < secondsNeeded) {
|
|
276
293
|
const maxAllowed = Math.floor((Date.now() - enrolledAt) / 1000) + maxFuture;
|
|
277
294
|
const diff = maxAllowed - secondsDone;
|
|
278
295
|
const timestamp = secondsDone + speed;
|
|
279
296
|
|
|
280
297
|
if (diff >= speed) {
|
|
281
|
-
const res = await this.videoProgress(quest.id, Math.min(secondsNeeded, timestamp + Math.random()));
|
|
298
|
+
const res = await this.videoProgress(quest.id, Math.min(secondsNeeded, timestamp + Math.random()), false);
|
|
282
299
|
completed = res.completed_at != null;
|
|
283
300
|
secondsDone = Math.min(secondsNeeded, timestamp);
|
|
284
301
|
}
|
|
@@ -291,22 +308,23 @@ class QuestManager extends BaseManager {
|
|
|
291
308
|
}
|
|
292
309
|
|
|
293
310
|
if (!completed) {
|
|
294
|
-
await this.videoProgress(quest.id, secondsNeeded);
|
|
311
|
+
await this.videoProgress(quest.id, secondsNeeded, false);
|
|
295
312
|
}
|
|
296
313
|
} else if (taskName === 'PLAY_ON_DESKTOP') {
|
|
297
314
|
const interval = 60;
|
|
298
315
|
|
|
299
316
|
while (!quest.isCompleted()) {
|
|
300
|
-
const
|
|
301
|
-
const res = await this.heartbeat(quest.id, quest.config.application.id, false);
|
|
317
|
+
const res = await this.heartbeat(quest.id, quest.config.application.id, false, false);
|
|
302
318
|
quest.updateUserStatus(res);
|
|
303
319
|
|
|
304
320
|
await this.timeout(interval * 1000);
|
|
305
321
|
}
|
|
306
322
|
|
|
307
|
-
const res = await this.heartbeat(quest.id, quest.config.application.id, true);
|
|
323
|
+
const res = await this.heartbeat(quest.id, quest.config.application.id, true, false);
|
|
308
324
|
quest.updateUserStatus(res);
|
|
309
325
|
}
|
|
326
|
+
|
|
327
|
+
await this.refreshCache();
|
|
310
328
|
}
|
|
311
329
|
|
|
312
330
|
/**
|
|
@@ -14,6 +14,10 @@ const { RelationshipTypes } = require('../util/Constants');
|
|
|
14
14
|
class RelationshipManager extends BaseManager {
|
|
15
15
|
constructor(client, users) {
|
|
16
16
|
super(client);
|
|
17
|
+
this._friendCache = new Collection();
|
|
18
|
+
this._blockedCache = new Collection();
|
|
19
|
+
this._incomingCache = new Collection();
|
|
20
|
+
this._outgoingCache = new Collection();
|
|
17
21
|
/**
|
|
18
22
|
* A collection of users this manager is caching. (Type: Number)
|
|
19
23
|
* @type {Collection<Snowflake, RelationshipType>}
|
|
@@ -36,10 +40,7 @@ class RelationshipManager extends BaseManager {
|
|
|
36
40
|
* @readonly
|
|
37
41
|
*/
|
|
38
42
|
get friendCache() {
|
|
39
|
-
|
|
40
|
-
.filter(value => value === RelationshipTypes.FRIEND)
|
|
41
|
-
.map((_, key) => [key, this.client.users.cache.get(key)]);
|
|
42
|
-
return new Collection(users);
|
|
43
|
+
return this._friendCache;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -48,10 +49,7 @@ class RelationshipManager extends BaseManager {
|
|
|
48
49
|
* @readonly
|
|
49
50
|
*/
|
|
50
51
|
get blockedCache() {
|
|
51
|
-
|
|
52
|
-
.filter(value => value === RelationshipTypes.BLOCKED)
|
|
53
|
-
.map((_, key) => [key, this.client.users.cache.get(key)]);
|
|
54
|
-
return new Collection(users);
|
|
52
|
+
return this._blockedCache;
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
/**
|
|
@@ -60,10 +58,7 @@ class RelationshipManager extends BaseManager {
|
|
|
60
58
|
* @readonly
|
|
61
59
|
*/
|
|
62
60
|
get incomingCache() {
|
|
63
|
-
|
|
64
|
-
.filter(value => value === RelationshipTypes.PENDING_INCOMING)
|
|
65
|
-
.map((_, key) => [key, this.client.users.cache.get(key)]);
|
|
66
|
-
return new Collection(users);
|
|
61
|
+
return this._incomingCache;
|
|
67
62
|
}
|
|
68
63
|
|
|
69
64
|
/**
|
|
@@ -72,10 +67,7 @@ class RelationshipManager extends BaseManager {
|
|
|
72
67
|
* @readonly
|
|
73
68
|
*/
|
|
74
69
|
get outgoingCache() {
|
|
75
|
-
|
|
76
|
-
.filter(value => value === RelationshipTypes.PENDING_OUTGOING)
|
|
77
|
-
.map((_, key) => [key, this.client.users.cache.get(key)]);
|
|
78
|
-
return new Collection(users);
|
|
70
|
+
return this._outgoingCache;
|
|
79
71
|
}
|
|
80
72
|
|
|
81
73
|
/**
|
|
@@ -106,10 +98,20 @@ class RelationshipManager extends BaseManager {
|
|
|
106
98
|
*/
|
|
107
99
|
_setup(users) {
|
|
108
100
|
if (!Array.isArray(users)) return;
|
|
101
|
+
// Reset caches so full fetches don't leave stale relationships behind
|
|
102
|
+
this.cache.clear();
|
|
103
|
+
this.friendNicknames.clear();
|
|
104
|
+
this.sinceCache.clear();
|
|
105
|
+
this._friendCache.clear();
|
|
106
|
+
this._blockedCache.clear();
|
|
107
|
+
this._incomingCache.clear();
|
|
108
|
+
this._outgoingCache.clear();
|
|
109
109
|
for (const relationShip of users) {
|
|
110
|
+
if (relationShip.user) this.client.users._add(relationShip.user);
|
|
110
111
|
this.friendNicknames.set(relationShip.id, relationShip.nickname);
|
|
111
112
|
this.cache.set(relationShip.id, relationShip.type);
|
|
112
113
|
this.sinceCache.set(relationShip.id, new Date(relationShip.since || 0));
|
|
114
|
+
this._updateRelationshipCaches(relationShip.id, relationShip.type);
|
|
113
115
|
}
|
|
114
116
|
}
|
|
115
117
|
|
|
@@ -123,7 +125,8 @@ class RelationshipManager extends BaseManager {
|
|
|
123
125
|
if (user instanceof GuildMember) return user.user.id;
|
|
124
126
|
if (user instanceof Message) return user.author.id;
|
|
125
127
|
if (user instanceof User) return user.id;
|
|
126
|
-
return user.match(/\d{17,19}/)?.[0] || null;
|
|
128
|
+
if (typeof user === 'string') return user.match(/\d{17,19}/)?.[0] || null;
|
|
129
|
+
return null;
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
/**
|
|
@@ -152,12 +155,28 @@ class RelationshipManager extends BaseManager {
|
|
|
152
155
|
const existing = this.cache.get(id);
|
|
153
156
|
if (existing && !existing.partial) return existing;
|
|
154
157
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
+
// Try incremental hydrate: if user already cached, avoid full sync
|
|
159
|
+
if (this.cache.has(id)) return this.cache.get(id);
|
|
160
|
+
const data = await this.client.api.users['@me']
|
|
161
|
+
.relationships(id)
|
|
162
|
+
.get()
|
|
163
|
+
.catch(() => null);
|
|
164
|
+
if (data) {
|
|
165
|
+
const type = data.type ?? RelationshipTypes.NONE;
|
|
166
|
+
this.cache.set(id, type);
|
|
167
|
+
this.friendNicknames.set(id, data.nickname);
|
|
168
|
+
this.sinceCache.set(id, new Date(data.since || 0));
|
|
169
|
+
this._updateRelationshipCaches(id, type);
|
|
170
|
+
if (data.user) this.client.users._add(data.user);
|
|
171
|
+
return type;
|
|
172
|
+
}
|
|
173
|
+
// Fallback: full refresh
|
|
174
|
+
const list = await this.client.api.users['@me'].relationships.get();
|
|
175
|
+
this._setup(list);
|
|
176
|
+
return this.cache.get(id) ?? null;
|
|
158
177
|
} else {
|
|
159
178
|
const data = await this.client.api.users['@me'].relationships.get();
|
|
160
|
-
|
|
179
|
+
this._setup(data);
|
|
161
180
|
return this;
|
|
162
181
|
}
|
|
163
182
|
}
|
|
@@ -168,19 +187,25 @@ class RelationshipManager extends BaseManager {
|
|
|
168
187
|
* @returns {Promise<boolean>}
|
|
169
188
|
*/
|
|
170
189
|
async deleteRelationship(user) {
|
|
171
|
-
throw new Error('Risky action, not finished yet.');
|
|
172
|
-
// eslint-disable-next-line no-unreachable
|
|
173
190
|
const id = this.resolveId(user);
|
|
191
|
+
if (!id) return false;
|
|
174
192
|
if (
|
|
175
|
-
![
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
![
|
|
194
|
+
RelationshipTypes.FRIEND,
|
|
195
|
+
RelationshipTypes.BLOCKED,
|
|
196
|
+
RelationshipTypes.PENDING_OUTGOING,
|
|
197
|
+
RelationshipTypes.PENDING_INCOMING,
|
|
198
|
+
].includes(this.cache.get(id))
|
|
178
199
|
) {
|
|
179
200
|
return Promise.resolve(false);
|
|
180
201
|
}
|
|
181
202
|
await this.client.api.users['@me'].relationships[id].delete({
|
|
182
203
|
DiscordContext: { location: 'ContextMenu' },
|
|
183
204
|
});
|
|
205
|
+
this.cache.delete(id);
|
|
206
|
+
this.friendNicknames.delete(id);
|
|
207
|
+
this.sinceCache.delete(id);
|
|
208
|
+
this._updateRelationshipCaches(id, RelationshipTypes.NONE);
|
|
184
209
|
return true;
|
|
185
210
|
}
|
|
186
211
|
|
|
@@ -190,16 +215,21 @@ class RelationshipManager extends BaseManager {
|
|
|
190
215
|
* @returns {Promise<boolean>}
|
|
191
216
|
*/
|
|
192
217
|
async sendFriendRequest(options) {
|
|
193
|
-
throw new Error('Risky action, not finished yet.');
|
|
194
|
-
// eslint-disable-next-line no-unreachable
|
|
195
218
|
const id = this.resolveId(options);
|
|
196
219
|
if (id) {
|
|
220
|
+
if ([RelationshipTypes.FRIEND, RelationshipTypes.PENDING_OUTGOING].includes(this.cache.get(id))) {
|
|
221
|
+
return Promise.resolve(false);
|
|
222
|
+
}
|
|
197
223
|
await this.client.api.users['@me'].relationships[id].put({
|
|
198
224
|
data: {},
|
|
199
225
|
DiscordContext: { location: 'ContextMenu' },
|
|
200
226
|
});
|
|
227
|
+
this.cache.set(id, RelationshipTypes.PENDING_OUTGOING);
|
|
228
|
+
this.sinceCache.set(id, new Date());
|
|
229
|
+
this._updateRelationshipCaches(id, RelationshipTypes.PENDING_OUTGOING);
|
|
201
230
|
} else {
|
|
202
231
|
const username = this.resolveUsername(options);
|
|
232
|
+
if (typeof username !== 'string') return false;
|
|
203
233
|
await this.client.api.users['@me'].relationships.post({
|
|
204
234
|
versioned: true,
|
|
205
235
|
data: {
|
|
@@ -218,9 +248,8 @@ class RelationshipManager extends BaseManager {
|
|
|
218
248
|
* @returns {Promise<boolean>}
|
|
219
249
|
*/
|
|
220
250
|
async addFriend(user) {
|
|
221
|
-
throw new Error('Risky action, not finished yet.');
|
|
222
|
-
// eslint-disable-next-line no-unreachable
|
|
223
251
|
const id = this.resolveId(user);
|
|
252
|
+
if (!id) return false;
|
|
224
253
|
// Check if already friends
|
|
225
254
|
if (this.cache.get(id) === RelationshipTypes.FRIEND) return Promise.resolve(false);
|
|
226
255
|
// Check if outgoing request
|
|
@@ -229,6 +258,9 @@ class RelationshipManager extends BaseManager {
|
|
|
229
258
|
data: { confirm_stranger_request: true },
|
|
230
259
|
DiscordContext: { location: 'Friends' },
|
|
231
260
|
});
|
|
261
|
+
this.cache.set(id, RelationshipTypes.FRIEND);
|
|
262
|
+
this.sinceCache.set(id, new Date());
|
|
263
|
+
this._updateRelationshipCaches(id, RelationshipTypes.FRIEND);
|
|
232
264
|
return true;
|
|
233
265
|
}
|
|
234
266
|
|
|
@@ -260,9 +292,8 @@ class RelationshipManager extends BaseManager {
|
|
|
260
292
|
* @returns {Promise<boolean>}
|
|
261
293
|
*/
|
|
262
294
|
async addBlocked(user) {
|
|
263
|
-
throw new Error('Risky action, not finished yet.');
|
|
264
|
-
// eslint-disable-next-line no-unreachable
|
|
265
295
|
const id = this.resolveId(user);
|
|
296
|
+
if (!id) return false;
|
|
266
297
|
// Check
|
|
267
298
|
if (this.cache.get(id) === RelationshipTypes.BLOCKED) return Promise.resolve(false);
|
|
268
299
|
await this.client.api.users['@me'].relationships[id].put({
|
|
@@ -271,8 +302,30 @@ class RelationshipManager extends BaseManager {
|
|
|
271
302
|
},
|
|
272
303
|
DiscordContext: { location: 'ContextMenu' },
|
|
273
304
|
});
|
|
305
|
+
this.cache.set(id, RelationshipTypes.BLOCKED);
|
|
306
|
+
this.friendNicknames.delete(id);
|
|
307
|
+
this.sinceCache.set(id, new Date());
|
|
308
|
+
this._updateRelationshipCaches(id, RelationshipTypes.BLOCKED);
|
|
274
309
|
return true;
|
|
275
310
|
}
|
|
311
|
+
|
|
312
|
+
_updateRelationshipCaches(id, type) {
|
|
313
|
+
this._friendCache.delete(id);
|
|
314
|
+
this._blockedCache.delete(id);
|
|
315
|
+
this._incomingCache.delete(id);
|
|
316
|
+
this._outgoingCache.delete(id);
|
|
317
|
+
const user = this.client.users.cache.get(id);
|
|
318
|
+
if (!user) return;
|
|
319
|
+
if (type === RelationshipTypes.FRIEND) {
|
|
320
|
+
this._friendCache.set(id, user);
|
|
321
|
+
} else if (type === RelationshipTypes.BLOCKED) {
|
|
322
|
+
this._blockedCache.set(id, user);
|
|
323
|
+
} else if (type === RelationshipTypes.PENDING_INCOMING) {
|
|
324
|
+
this._incomingCache.set(id, user);
|
|
325
|
+
} else if (type === RelationshipTypes.PENDING_OUTGOING) {
|
|
326
|
+
this._outgoingCache.set(id, user);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
276
329
|
}
|
|
277
330
|
|
|
278
331
|
module.exports = RelationshipManager;
|
|
@@ -4,10 +4,10 @@ const { setInterval } = require('node:timers');
|
|
|
4
4
|
const { Collection } = require('@discordjs/collection');
|
|
5
5
|
const Invite = require('./Invite');
|
|
6
6
|
const User = require('./User');
|
|
7
|
+
const { Error, TypeError } = require('../errors');
|
|
7
8
|
const DataResolver = require('../util/DataResolver');
|
|
8
9
|
const PremiumUsageFlags = require('../util/PremiumUsageFlags');
|
|
9
10
|
const PurchasedFlags = require('../util/PurchasedFlags');
|
|
10
|
-
const { Error, TypeError } = require('../errors');
|
|
11
11
|
const Util = require('../util/Util');
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -117,6 +117,46 @@ class ClientUser extends User {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* A collection of friends for the logged in user (user accounts only).
|
|
122
|
+
* @type {Collection<Snowflake, User>}
|
|
123
|
+
* @readonly
|
|
124
|
+
* @deprecated Use {@link Client#relationships} for the full API surface.
|
|
125
|
+
*/
|
|
126
|
+
get friends() {
|
|
127
|
+
return this.client.relationships.friendCache;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* A collection of blocked users for the logged in user (user accounts only).
|
|
132
|
+
* @type {Collection<Snowflake, User>}
|
|
133
|
+
* @readonly
|
|
134
|
+
* @deprecated Use {@link Client#relationships} for the full API surface.
|
|
135
|
+
*/
|
|
136
|
+
get blocked() {
|
|
137
|
+
return this.client.relationships.blockedCache;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* A collection of pending incoming friend requests for the logged in user (user accounts only).
|
|
142
|
+
* @type {Collection<Snowflake, User>}
|
|
143
|
+
* @readonly
|
|
144
|
+
* @deprecated Use {@link Client#relationships} for the full API surface.
|
|
145
|
+
*/
|
|
146
|
+
get pending() {
|
|
147
|
+
return this.client.relationships.incomingCache;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* A collection of outgoing friend requests for the logged in user (user accounts only).
|
|
152
|
+
* @type {Collection<Snowflake, User>}
|
|
153
|
+
* @readonly
|
|
154
|
+
* @deprecated Use {@link Client#relationships} for the full API surface.
|
|
155
|
+
*/
|
|
156
|
+
get outgoing() {
|
|
157
|
+
return this.client.relationships.outgoingCache;
|
|
158
|
+
}
|
|
159
|
+
|
|
120
160
|
/**
|
|
121
161
|
* Represents the client user's presence
|
|
122
162
|
* @type {ClientPresence}
|
package/src/structures/Guild.js
CHANGED
|
@@ -1746,7 +1746,7 @@ class Guild extends AnonymousGuild {
|
|
|
1746
1746
|
const data = await this.client.api.guilds(this.id).messages.search.get({ query });
|
|
1747
1747
|
|
|
1748
1748
|
if (limit && data.messages) {
|
|
1749
|
-
//
|
|
1749
|
+
// Data.messages est souvent un tableau de tableaux dans l'API search
|
|
1750
1750
|
data.messages = data.messages.flat().slice(0, limit);
|
|
1751
1751
|
}
|
|
1752
1752
|
|
package/typings/enums.d.ts
CHANGED
|
@@ -333,8 +333,6 @@ export enum NameplatePalette {
|
|
|
333
333
|
White = 'white',
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
-
|
|
337
|
-
|
|
338
336
|
export const enum OverwriteTypes {
|
|
339
337
|
role = 0,
|
|
340
338
|
member = 1,
|
|
@@ -437,3 +435,103 @@ export const enum ApplicationType {
|
|
|
437
435
|
*/
|
|
438
436
|
CREATOR_MONETIZATION = 4,
|
|
439
437
|
}
|
|
438
|
+
|
|
439
|
+
export enum ClientEvents {
|
|
440
|
+
RateLimit = 'rateLimit',
|
|
441
|
+
InvalidRequestWarning = 'invalidRequestWarning',
|
|
442
|
+
ApiResponse = 'apiResponse',
|
|
443
|
+
ApiRequest = 'apiRequest',
|
|
444
|
+
ClientReady = 'ready',
|
|
445
|
+
ApplicationCommandCreate = 'applicationCommandCreate',
|
|
446
|
+
ApplicationCommandDelete = 'applicationCommandDelete',
|
|
447
|
+
ApplicationCommandUpdate = 'applicationCommandUpdate',
|
|
448
|
+
ApplicationCommandPermissionsUpdate = 'applicationCommandPermissionsUpdate',
|
|
449
|
+
AutoModerationActionExecution = 'autoModerationActionExecution',
|
|
450
|
+
AutoModerationRuleCreate = 'autoModerationRuleCreate',
|
|
451
|
+
AutoModerationRuleDelete = 'autoModerationRuleDelete',
|
|
452
|
+
AutoModerationRuleUpdate = 'autoModerationRuleUpdate',
|
|
453
|
+
GuildAvailable = 'guildAvailable',
|
|
454
|
+
GuildCreate = 'guildCreate',
|
|
455
|
+
GuildDelete = 'guildDelete',
|
|
456
|
+
GuildUpdate = 'guildUpdate',
|
|
457
|
+
GuildUnavailable = 'guildUnavailable',
|
|
458
|
+
GuildMemberAdd = 'guildMemberAdd',
|
|
459
|
+
GuildMemberRemove = 'guildMemberRemove',
|
|
460
|
+
GuildMemberUpdate = 'guildMemberUpdate',
|
|
461
|
+
GuildMemberAvailable = 'guildMemberAvailable',
|
|
462
|
+
GuildMembersChunk = 'guildMembersChunk',
|
|
463
|
+
GuildIntegrationsUpdate = 'guildIntegrationsUpdate',
|
|
464
|
+
GuildRoleCreate = 'roleCreate',
|
|
465
|
+
GuildRoleDelete = 'roleDelete',
|
|
466
|
+
InviteCreate = 'inviteCreate',
|
|
467
|
+
InviteDelete = 'inviteDelete',
|
|
468
|
+
GuildRoleUpdate = 'roleUpdate',
|
|
469
|
+
GuildEmojiCreate = 'emojiCreate',
|
|
470
|
+
GuildEmojiDelete = 'emojiDelete',
|
|
471
|
+
GuildEmojiUpdate = 'emojiUpdate',
|
|
472
|
+
GuildBanAdd = 'guildBanAdd',
|
|
473
|
+
GuildBanRemove = 'guildBanRemove',
|
|
474
|
+
ChannelCreate = 'channelCreate',
|
|
475
|
+
ChannelDelete = 'channelDelete',
|
|
476
|
+
ChannelUpdate = 'channelUpdate',
|
|
477
|
+
ChannelPinsUpdate = 'channelPinsUpdate',
|
|
478
|
+
MessageCreate = 'messageCreate',
|
|
479
|
+
MessageDelete = 'messageDelete',
|
|
480
|
+
MessageUpdate = 'messageUpdate',
|
|
481
|
+
MessageBulkDelete = 'messageDeleteBulk',
|
|
482
|
+
MessageReactionAdd = 'messageReactionAdd',
|
|
483
|
+
MessageReactionRemove = 'messageReactionRemove',
|
|
484
|
+
MessageReactionRemoveAll = 'messageReactionRemoveAll',
|
|
485
|
+
MessageReactionRemoveEmoji = 'messageReactionRemoveEmoji',
|
|
486
|
+
ThreadCreate = 'threadCreate',
|
|
487
|
+
ThreadDelete = 'threadDelete',
|
|
488
|
+
ThreadUpdate = 'threadUpdate',
|
|
489
|
+
ThreadListSync = 'threadListSync',
|
|
490
|
+
ThreadMemberUpdate = 'threadMemberUpdate',
|
|
491
|
+
ThreadMembersUpdate = 'threadMembersUpdate',
|
|
492
|
+
UserUpdate = 'userUpdate',
|
|
493
|
+
PresenceUpdate = 'presenceUpdate',
|
|
494
|
+
VoiceServerUpdate = 'voiceServerUpdate',
|
|
495
|
+
VoiceStateUpdate = 'voiceStateUpdate',
|
|
496
|
+
TypingStart = 'typingStart',
|
|
497
|
+
WebhooksUpdate = 'webhookUpdate',
|
|
498
|
+
Error = 'error',
|
|
499
|
+
Warn = 'warn',
|
|
500
|
+
Debug = 'debug',
|
|
501
|
+
CacheSweep = 'cacheSweep',
|
|
502
|
+
ShardDisconnect = 'shardDisconnect',
|
|
503
|
+
ShardError = 'shardError',
|
|
504
|
+
ShardReconnecting = 'shardReconnecting',
|
|
505
|
+
ShardReady = 'shardReady',
|
|
506
|
+
ShardResume = 'shardResume',
|
|
507
|
+
Invalidated = 'invalidated',
|
|
508
|
+
Raw = 'raw',
|
|
509
|
+
StageInstanceCreate = 'stageInstanceCreate',
|
|
510
|
+
StageInstanceUpdate = 'stageInstanceUpdate',
|
|
511
|
+
StageInstanceDelete = 'stageInstanceDelete',
|
|
512
|
+
GuildStickerCreate = 'stickerCreate',
|
|
513
|
+
GuildStickerDelete = 'stickerDelete',
|
|
514
|
+
GuildStickerUpdate = 'stickerUpdate',
|
|
515
|
+
GuildScheduledEventCreate = 'guildScheduledEventCreate',
|
|
516
|
+
GuildScheduledEventUpdate = 'guildScheduledEventUpdate',
|
|
517
|
+
GuildScheduledEventDelete = 'guildScheduledEventDelete',
|
|
518
|
+
GuildScheduledEventUserAdd = 'guildScheduledEventUserAdd',
|
|
519
|
+
GuildScheduledEventUserRemove = 'guildScheduledEventUserRemove',
|
|
520
|
+
GuildAuditLogEntryCreate = 'guildAuditLogEntryCreate',
|
|
521
|
+
UnhandledPacket = 'unhandledPacket',
|
|
522
|
+
RelationshipAdd = 'relationshipAdd',
|
|
523
|
+
RelationshipUpdate = 'relationshipUpdate',
|
|
524
|
+
RelationshipRemove = 'relationshipRemove',
|
|
525
|
+
ChannelRecipientAdd = 'channelRecipientAdd',
|
|
526
|
+
ChannelRecipientRemove = 'channelRecipientRemove',
|
|
527
|
+
InteractionCreate = 'interactionCreate',
|
|
528
|
+
InteractionModalCreate = 'interactionModalCreate',
|
|
529
|
+
CallCreate = 'callCreate',
|
|
530
|
+
CallUpdate = 'callUpdate',
|
|
531
|
+
CallDelete = 'callDelete',
|
|
532
|
+
MessagePollVoteAdd = 'messagePollVoteAdd',
|
|
533
|
+
MessagePollVoteRemove = 'messagePollVoteRemove',
|
|
534
|
+
VoiceChannelEffectSend = 'voiceChannelEffectSend',
|
|
535
|
+
VoiceBroadcastSubscribe = 'subscribe',
|
|
536
|
+
VoiceBroadcastUnsubscribe = 'unsubscribe',
|
|
537
|
+
}
|
package/typings/index.d.ts
CHANGED
|
@@ -889,6 +889,9 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
|
|
889
889
|
public fetchGuildWidget(guild: GuildResolvable): Promise<Widget>;
|
|
890
890
|
public refreshAttachmentURL(...urls: string[]): Promise<{ original: string; refreshed: string }[]>;
|
|
891
891
|
public sleep(timeout: number): Promise<void>;
|
|
892
|
+
/** @deprecated User accounts only */
|
|
893
|
+
public syncGuilds(guilds?: Guild[] | Collection<Snowflake, Guild>): void;
|
|
894
|
+
public fetchUser(user: UserResolvable, options?: BaseFetchOptions): Promise<User>;
|
|
892
895
|
public login(token?: string): Promise<string>;
|
|
893
896
|
/** @deprecated This method will not be updated until I find the most convenient way to implement MFA. */
|
|
894
897
|
public passLogin(email: string, password: string): Promise<string | null>;
|
|
@@ -904,7 +907,8 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
|
|
904
907
|
): Promise<Guild | DMChannel | GroupDMChannel>;
|
|
905
908
|
public redeemNitro(nitro: string, channel?: TextChannelResolvable, paymentSourceId?: Snowflake): Promise<any>;
|
|
906
909
|
public authorizeURL(urlOAuth2: string, options?: OAuth2AuthorizeOptions): Promise<{ location: string }>;
|
|
907
|
-
public installUserApps(applicationId: Snowflake): Promise<
|
|
910
|
+
public installUserApps(applicationId: Snowflake, scopes?: string[] | string): Promise<boolean>;
|
|
911
|
+
public unInstallUserApp(applicationId: Snowflake): Promise<boolean>;
|
|
908
912
|
public deauthorize(id: Snowflake, type?: 'application' | 'token'): Promise<void>;
|
|
909
913
|
public authorizedApplications(): Promise<
|
|
910
914
|
Collection<
|
|
@@ -1003,6 +1007,10 @@ export class ClientUser extends User {
|
|
|
1003
1007
|
public setActivity(name: string, options?: Omit<ActivityOptions, 'name'>): ClientPresence;
|
|
1004
1008
|
public setAFK(afk?: boolean, shardId?: number | number[]): ClientPresence;
|
|
1005
1009
|
public setAvatar(avatar: BufferResolvable | Base64Resolvable | null): Promise<this>;
|
|
1010
|
+
public readonly friends: Collection<Snowflake, User>;
|
|
1011
|
+
public readonly blocked: Collection<Snowflake, User>;
|
|
1012
|
+
public readonly pending: Collection<Snowflake, User>;
|
|
1013
|
+
public readonly outgoing: Collection<Snowflake, User>;
|
|
1006
1014
|
public setPresence(data: PresenceData): ClientPresence;
|
|
1007
1015
|
public setStatus(status: PresenceStatusData, shardId?: number | number[]): ClientPresence;
|
|
1008
1016
|
public setUsername(username: string, password: string): Promise<this>;
|
|
@@ -1033,7 +1041,12 @@ export class ClientUser extends User {
|
|
|
1033
1041
|
public addWidget(type: WidgetType, gameId: string, comment?: string | null, tags?: string[]): Promise<any>;
|
|
1034
1042
|
public delWidget(type: WidgetType, gameId?: string): Promise<any>;
|
|
1035
1043
|
public widgetsList(): Promise<WidgetsResponse>;
|
|
1036
|
-
public setNameStyle(
|
|
1044
|
+
public setNameStyle(
|
|
1045
|
+
fontName: FontName | number,
|
|
1046
|
+
effectName: EffectName | number,
|
|
1047
|
+
color1: number | string,
|
|
1048
|
+
color2?: number | string | null,
|
|
1049
|
+
): Promise<this>;
|
|
1037
1050
|
}
|
|
1038
1051
|
|
|
1039
1052
|
export class Options extends null {
|