lunibee 0.1.6 → 0.1.7
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/README.md +3 -3
- package/dist/builders/commands.d.ts +37 -0
- package/dist/builders/components.d.ts +19 -12
- package/dist/builders/embed.d.ts +3 -1
- package/dist/builders/index.d.ts +1 -1
- package/dist/builders/index.js +146 -19
- package/dist/builders/index.js.map +8 -7
- package/dist/collection/index.d.ts +30 -0
- package/dist/collection/index.js +78 -5
- package/dist/collection/index.js.map +4 -4
- package/dist/core/events.d.ts +2 -0
- package/dist/core/index.d.ts +38 -0
- package/dist/core/index.js +754 -175
- package/dist/core/index.js.map +24 -22
- package/dist/core/permissions.d.ts +112 -53
- package/dist/formatters/index.d.ts +43 -3
- package/dist/formatters/index.js +64 -1
- package/dist/formatters/index.js.map +3 -3
- package/dist/handlers/index.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1762 -291
- package/dist/index.js.map +43 -38
- package/dist/managers/emoji.d.ts +38 -0
- package/dist/managers/guild.d.ts +112 -1
- package/dist/managers/index.d.ts +31 -1
- package/dist/managers/index.js +803 -77
- package/dist/managers/index.js.map +21 -20
- package/dist/rest/index.d.ts +101 -11
- package/dist/rest/index.js +301 -45
- package/dist/rest/index.js.map +8 -6
- package/dist/rest/redis.d.ts +37 -0
- package/dist/rest/routes.d.ts +22 -0
- package/dist/rest/store.d.ts +38 -0
- package/dist/rest/webhook.d.ts +2 -2
- package/dist/sharding/cluster.d.ts +61 -0
- package/dist/sharding/index.d.ts +8 -0
- package/dist/sharding/index.js +286 -18
- package/dist/sharding/index.js.map +8 -7
- package/dist/structures/audit-log.d.ts +26 -0
- package/dist/structures/base.d.ts +32 -0
- package/dist/structures/index.d.ts +29 -1
- package/dist/structures/index.js +1022 -86
- package/dist/structures/index.js.map +14 -10
- package/dist/structures/resources.d.ts +192 -4
- package/dist/types/index.d.ts +76 -0
- package/dist/types/index.js.map +2 -2
- package/dist/utils/index.js.map +2 -2
- package/dist/voice/index.d.ts +88 -0
- package/dist/voice/index.js +204 -5
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/index.d.ts +40 -1
- package/dist/ws/index.js +102 -18
- package/dist/ws/index.js.map +4 -4
- package/package.json +16 -16
- package/dist/structures/permissions.d.ts +0 -73
package/dist/core/index.js
CHANGED
|
@@ -107,58 +107,57 @@ var Permissions = {
|
|
|
107
107
|
SendPolls: 1n << 49n,
|
|
108
108
|
UseExternalApps: 1n << 50n
|
|
109
109
|
};
|
|
110
|
-
var PermissionFlagsBits
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
})(PermissionFlagsBits ||= {});
|
|
110
|
+
var PermissionFlagsBits = {
|
|
111
|
+
CreateInstantInvite: 1n << 0n,
|
|
112
|
+
KickMembers: 1n << 1n,
|
|
113
|
+
BanMembers: 1n << 2n,
|
|
114
|
+
Administrator: 1n << 3n,
|
|
115
|
+
ManageChannels: 1n << 4n,
|
|
116
|
+
ManageGuild: 1n << 5n,
|
|
117
|
+
AddReactions: 1n << 6n,
|
|
118
|
+
ViewAuditLog: 1n << 7n,
|
|
119
|
+
PrioritySpeaker: 1n << 8n,
|
|
120
|
+
Stream: 1n << 9n,
|
|
121
|
+
ViewChannel: 1n << 10n,
|
|
122
|
+
SendMessages: 1n << 11n,
|
|
123
|
+
SendTTSMessages: 1n << 12n,
|
|
124
|
+
ManageMessages: 1n << 13n,
|
|
125
|
+
EmbedLinks: 1n << 14n,
|
|
126
|
+
AttachFiles: 1n << 15n,
|
|
127
|
+
ReadMessageHistory: 1n << 16n,
|
|
128
|
+
MentionEveryone: 1n << 17n,
|
|
129
|
+
UseExternalEmojis: 1n << 18n,
|
|
130
|
+
ViewGuildInsights: 1n << 19n,
|
|
131
|
+
Connect: 1n << 20n,
|
|
132
|
+
Speak: 1n << 21n,
|
|
133
|
+
MuteMembers: 1n << 22n,
|
|
134
|
+
DeafenMembers: 1n << 23n,
|
|
135
|
+
MoveMembers: 1n << 24n,
|
|
136
|
+
UseVAD: 1n << 25n,
|
|
137
|
+
ChangeNickname: 1n << 26n,
|
|
138
|
+
ManageNicknames: 1n << 27n,
|
|
139
|
+
ManageRoles: 1n << 28n,
|
|
140
|
+
ManageWebhooks: 1n << 29n,
|
|
141
|
+
ManageGuildExpressions: 1n << 30n,
|
|
142
|
+
UseApplicationCommands: 1n << 31n,
|
|
143
|
+
RequestToSpeak: 1n << 32n,
|
|
144
|
+
ManageEvents: 1n << 33n,
|
|
145
|
+
ManageThreads: 1n << 34n,
|
|
146
|
+
CreatePublicThreads: 1n << 35n,
|
|
147
|
+
CreatePrivateThreads: 1n << 36n,
|
|
148
|
+
UseExternalStickers: 1n << 37n,
|
|
149
|
+
SendMessagesInThreads: 1n << 38n,
|
|
150
|
+
UseEmbeddedActivities: 1n << 39n,
|
|
151
|
+
ModerateMembers: 1n << 40n,
|
|
152
|
+
ViewCreatorMonetizationAnalytics: 1n << 41n,
|
|
153
|
+
UseSoundboard: 1n << 42n,
|
|
154
|
+
CreateGuildExpressions: 1n << 43n,
|
|
155
|
+
CreateEvents: 1n << 44n,
|
|
156
|
+
UseExternalSounds: 1n << 45n,
|
|
157
|
+
SendVoiceMessages: 1n << 46n,
|
|
158
|
+
SendPolls: 1n << 49n,
|
|
159
|
+
UseExternalApps: 1n << 50n
|
|
160
|
+
};
|
|
162
161
|
|
|
163
162
|
class PermissionSet {
|
|
164
163
|
bitfield;
|
|
@@ -403,7 +402,7 @@ class PermissionSet {
|
|
|
403
402
|
if (permission in Permissions)
|
|
404
403
|
return Permissions[permission];
|
|
405
404
|
if (permission in PermissionFlagsBits)
|
|
406
|
-
return
|
|
405
|
+
return PermissionFlagsBits[permission];
|
|
407
406
|
const lower = permission.charAt(0).toLowerCase() + permission.slice(1);
|
|
408
407
|
if (lower in Permission)
|
|
409
408
|
return Permission[lower];
|
|
@@ -424,6 +423,8 @@ class PermissionsBitField extends PermissionSet {
|
|
|
424
423
|
var ClientEvent;
|
|
425
424
|
((ClientEvent2) => {
|
|
426
425
|
ClientEvent2["Ready"] = "ready";
|
|
426
|
+
ClientEvent2["Resumed"] = "resumed";
|
|
427
|
+
ClientEvent2["InvalidSession"] = "invalidSession";
|
|
427
428
|
ClientEvent2["Raw"] = "raw";
|
|
428
429
|
ClientEvent2["Error"] = "error";
|
|
429
430
|
ClientEvent2["Open"] = "open";
|
|
@@ -486,6 +487,76 @@ var ClientEvent;
|
|
|
486
487
|
ClientEvent2["TypingStart"] = "typingStart";
|
|
487
488
|
ClientEvent2["InteractionCreate"] = "interactionCreate";
|
|
488
489
|
})(ClientEvent ||= {});
|
|
490
|
+
// packages/core/src/collector.ts
|
|
491
|
+
import { EventEmitter } from "events";
|
|
492
|
+
|
|
493
|
+
class Collector extends EventEmitter {
|
|
494
|
+
collected = new Map;
|
|
495
|
+
options;
|
|
496
|
+
ended = false;
|
|
497
|
+
endReason;
|
|
498
|
+
totalProcessed = 0;
|
|
499
|
+
#timeoutTimer;
|
|
500
|
+
constructor(options = {}) {
|
|
501
|
+
super();
|
|
502
|
+
this.options = options;
|
|
503
|
+
if (options.time && options.time > 0) {
|
|
504
|
+
this.#timeoutTimer = setTimeout(() => {
|
|
505
|
+
this.stop("time");
|
|
506
|
+
}, options.time);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
async handle(key, item) {
|
|
510
|
+
if (this.ended)
|
|
511
|
+
return false;
|
|
512
|
+
this.totalProcessed++;
|
|
513
|
+
const reachedProcessed = !!this.options.maxProcessed && this.totalProcessed >= this.options.maxProcessed;
|
|
514
|
+
let passed = true;
|
|
515
|
+
if (this.options.filter)
|
|
516
|
+
passed = !!await this.options.filter(item);
|
|
517
|
+
if (this.ended)
|
|
518
|
+
return false;
|
|
519
|
+
if (!passed) {
|
|
520
|
+
if (reachedProcessed)
|
|
521
|
+
this.stop("processedLimit");
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
this.collected.set(key, item);
|
|
525
|
+
this.emit("collect", item);
|
|
526
|
+
if (this.options.max && this.collected.size >= this.options.max) {
|
|
527
|
+
this.stop("limit");
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
if (reachedProcessed) {
|
|
531
|
+
this.stop("processedLimit");
|
|
532
|
+
return true;
|
|
533
|
+
}
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
stop(reason = "user") {
|
|
537
|
+
if (this.ended)
|
|
538
|
+
return;
|
|
539
|
+
this.ended = true;
|
|
540
|
+
this.endReason = reason;
|
|
541
|
+
if (this.#timeoutTimer)
|
|
542
|
+
clearTimeout(this.#timeoutTimer);
|
|
543
|
+
this.emit("end", this.collected, reason);
|
|
544
|
+
this.removeAllListeners();
|
|
545
|
+
}
|
|
546
|
+
next() {
|
|
547
|
+
return new Promise((resolve, reject) => {
|
|
548
|
+
if (this.ended) {
|
|
549
|
+
return reject(new Error(`Collector already ended: ${this.endReason ?? "unknown"}`));
|
|
550
|
+
}
|
|
551
|
+
this.once("collect", (item) => {
|
|
552
|
+
resolve(item);
|
|
553
|
+
});
|
|
554
|
+
this.once("end", (_collected, reason) => {
|
|
555
|
+
reject(new Error(`Collector ended before item was collected: ${reason}`));
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
}
|
|
489
560
|
// packages/types/src/index.ts
|
|
490
561
|
var GatewayIntentBits = {
|
|
491
562
|
Guilds: 1 << 0,
|
|
@@ -716,6 +787,75 @@ class Collection extends Map {
|
|
|
716
787
|
}
|
|
717
788
|
return result;
|
|
718
789
|
}
|
|
790
|
+
partition(predicate) {
|
|
791
|
+
const pass = new Collection;
|
|
792
|
+
const fail = new Collection;
|
|
793
|
+
for (const [key, value] of this) {
|
|
794
|
+
if (predicate(value, key, this))
|
|
795
|
+
pass.set(key, value);
|
|
796
|
+
else
|
|
797
|
+
fail.set(key, value);
|
|
798
|
+
}
|
|
799
|
+
return [pass, fail];
|
|
800
|
+
}
|
|
801
|
+
tap(fn) {
|
|
802
|
+
fn(this);
|
|
803
|
+
return this;
|
|
804
|
+
}
|
|
805
|
+
flatMap(transform) {
|
|
806
|
+
const result = [];
|
|
807
|
+
for (const [key, value] of this) {
|
|
808
|
+
for (const item of transform(value, key, this))
|
|
809
|
+
result.push(item);
|
|
810
|
+
}
|
|
811
|
+
return result;
|
|
812
|
+
}
|
|
813
|
+
reduce(fn, initialValue) {
|
|
814
|
+
let acc = initialValue;
|
|
815
|
+
for (const [key, value] of this)
|
|
816
|
+
acc = fn(acc, value, key, this);
|
|
817
|
+
return acc;
|
|
818
|
+
}
|
|
819
|
+
sorted(comparator) {
|
|
820
|
+
const decorated = [...this.entries()].map((entry, index) => ({
|
|
821
|
+
entry,
|
|
822
|
+
index
|
|
823
|
+
}));
|
|
824
|
+
if (comparator)
|
|
825
|
+
decorated.sort((x, y) => {
|
|
826
|
+
const comparison = comparator(x.entry[1], y.entry[1], x.entry[0], y.entry[0]);
|
|
827
|
+
return comparison !== 0 ? comparison : x.index - y.index;
|
|
828
|
+
});
|
|
829
|
+
const result = new Collection;
|
|
830
|
+
for (const { entry } of decorated)
|
|
831
|
+
result.set(entry[0], entry[1]);
|
|
832
|
+
return result;
|
|
833
|
+
}
|
|
834
|
+
random() {
|
|
835
|
+
const arr = [...this.values()];
|
|
836
|
+
if (!arr.length)
|
|
837
|
+
return;
|
|
838
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
839
|
+
}
|
|
840
|
+
randomKey() {
|
|
841
|
+
const arr = [...this.keys()];
|
|
842
|
+
if (!arr.length)
|
|
843
|
+
return;
|
|
844
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
845
|
+
}
|
|
846
|
+
at(index) {
|
|
847
|
+
const arr = [...this.values()];
|
|
848
|
+
const i = index < 0 ? arr.length + index : index;
|
|
849
|
+
return arr[i];
|
|
850
|
+
}
|
|
851
|
+
keyAt(index) {
|
|
852
|
+
const arr = [...this.keys()];
|
|
853
|
+
const i = index < 0 ? arr.length + index : index;
|
|
854
|
+
return arr[i];
|
|
855
|
+
}
|
|
856
|
+
toJSON() {
|
|
857
|
+
return [...this.entries()];
|
|
858
|
+
}
|
|
719
859
|
}
|
|
720
860
|
|
|
721
861
|
// packages/managers/src/base.ts
|
|
@@ -787,7 +927,7 @@ class ResourceManager extends Manager {
|
|
|
787
927
|
// packages/rest/package.json
|
|
788
928
|
var package_default = {
|
|
789
929
|
name: "@lunibee/rest",
|
|
790
|
-
version: "0.1.
|
|
930
|
+
version: "0.1.7",
|
|
791
931
|
type: "module",
|
|
792
932
|
module: "./src/index.ts",
|
|
793
933
|
types: "./src/index.ts",
|
|
@@ -796,6 +936,45 @@ var package_default = {
|
|
|
796
936
|
}
|
|
797
937
|
};
|
|
798
938
|
|
|
939
|
+
// packages/rest/src/store.ts
|
|
940
|
+
class MemoryRateLimitStore {
|
|
941
|
+
#buckets = new Map;
|
|
942
|
+
#routeBuckets = new Map;
|
|
943
|
+
#globalResetAt = 0;
|
|
944
|
+
static #PRUNE_INTERVAL = 60000;
|
|
945
|
+
#lastPruneAt = 0;
|
|
946
|
+
getBucketHash(route) {
|
|
947
|
+
return this.#routeBuckets.get(route);
|
|
948
|
+
}
|
|
949
|
+
setBucketHash(route, hash) {
|
|
950
|
+
this.#routeBuckets.set(route, hash);
|
|
951
|
+
}
|
|
952
|
+
getBucket(key) {
|
|
953
|
+
return this.#buckets.get(key);
|
|
954
|
+
}
|
|
955
|
+
updateBucket(key, state) {
|
|
956
|
+
this.#buckets.set(key, state);
|
|
957
|
+
const now = Date.now();
|
|
958
|
+
if (now - this.#lastPruneAt >= MemoryRateLimitStore.#PRUNE_INTERVAL) {
|
|
959
|
+
this.#lastPruneAt = now;
|
|
960
|
+
this.prune();
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
prune(maxAge = 0) {
|
|
964
|
+
const cutoff = Date.now() - Math.max(0, maxAge);
|
|
965
|
+
for (const [key, state] of this.#buckets) {
|
|
966
|
+
if (state.resetAt <= cutoff)
|
|
967
|
+
this.#buckets.delete(key);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
getGlobalReset() {
|
|
971
|
+
return this.#globalResetAt;
|
|
972
|
+
}
|
|
973
|
+
setGlobalReset(resetAt) {
|
|
974
|
+
this.#globalResetAt = resetAt;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
799
978
|
// packages/rest/src/routes.ts
|
|
800
979
|
var Routes = {
|
|
801
980
|
user: () => "/users/@me",
|
|
@@ -841,7 +1020,18 @@ var Routes = {
|
|
|
841
1020
|
guildAutoModerationRule: (guildId, ruleId) => `/guilds/${snowflake(guildId, "Guild ID")}/auto-moderation/rules/${snowflake(ruleId, "Rule ID")}`,
|
|
842
1021
|
voiceRegions: () => "/voice/regions",
|
|
843
1022
|
gateway: () => "/gateway",
|
|
844
|
-
gatewayBot: () => "/gateway/bot"
|
|
1023
|
+
gatewayBot: () => "/gateway/bot",
|
|
1024
|
+
guildAuditLog: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/audit-logs`,
|
|
1025
|
+
guildMembers: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/members`,
|
|
1026
|
+
guildWelcomeScreen: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/welcome-screen`,
|
|
1027
|
+
guildOnboarding: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/onboarding`,
|
|
1028
|
+
guildPrune: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/prune`,
|
|
1029
|
+
stageInstances: () => "/stage-instances",
|
|
1030
|
+
stageInstanceByChannel: (channelId) => `/stage-instances/${snowflake(channelId, "Channel ID")}`,
|
|
1031
|
+
invite: (code) => `/invites/${encodeURIComponent(code)}`,
|
|
1032
|
+
guildVanity: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/vanity-url`,
|
|
1033
|
+
guildEmoji: (guildId, emojiId) => emojiId ? `/guilds/${snowflake(guildId, "Guild ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/emojis`,
|
|
1034
|
+
applicationEmoji: (applicationId, emojiId) => emojiId ? `/applications/${snowflake(applicationId, "Application ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/emojis`
|
|
845
1035
|
};
|
|
846
1036
|
function snowflake(value, field) {
|
|
847
1037
|
if (!/^\d{1,20}$/.test(value))
|
|
@@ -869,6 +1059,49 @@ class RESTError extends Error {
|
|
|
869
1059
|
var LIBRARY_VERSION = package_default.version;
|
|
870
1060
|
var LIBRARY_URL = "https://github.com/Ekretos/lunibee";
|
|
871
1061
|
var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${package_default.version})`;
|
|
1062
|
+
var REQUEST_DATA_KEYS = new Set([
|
|
1063
|
+
"body",
|
|
1064
|
+
"files",
|
|
1065
|
+
"query",
|
|
1066
|
+
"headers",
|
|
1067
|
+
"reason",
|
|
1068
|
+
"auth",
|
|
1069
|
+
"signal"
|
|
1070
|
+
]);
|
|
1071
|
+
function isRequestData(value) {
|
|
1072
|
+
if (value === null || typeof value !== "object")
|
|
1073
|
+
return false;
|
|
1074
|
+
if (Array.isArray(value))
|
|
1075
|
+
return false;
|
|
1076
|
+
if (typeof FormData !== "undefined" && value instanceof FormData)
|
|
1077
|
+
return false;
|
|
1078
|
+
if (value instanceof Blob || value instanceof Uint8Array || value instanceof ArrayBuffer)
|
|
1079
|
+
return false;
|
|
1080
|
+
const keys = Object.keys(value);
|
|
1081
|
+
if (keys.length === 0)
|
|
1082
|
+
return false;
|
|
1083
|
+
return keys.every((key) => REQUEST_DATA_KEYS.has(key));
|
|
1084
|
+
}
|
|
1085
|
+
function serializeQuery(query) {
|
|
1086
|
+
if (query === undefined)
|
|
1087
|
+
return "";
|
|
1088
|
+
if (typeof query === "string")
|
|
1089
|
+
return query.length === 0 || query.startsWith("?") ? query : `?${query}`;
|
|
1090
|
+
const params = query instanceof URLSearchParams ? query : new URLSearchParams(Object.entries(query).flatMap(([key, value]) => value === undefined || value === null ? [] : [[key, String(value)]]));
|
|
1091
|
+
const serialized = params.toString();
|
|
1092
|
+
return serialized.length === 0 ? "" : `?${serialized}`;
|
|
1093
|
+
}
|
|
1094
|
+
function majorParameter(path) {
|
|
1095
|
+
const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/.exec(path);
|
|
1096
|
+
if (!match)
|
|
1097
|
+
return "@none";
|
|
1098
|
+
if (match[1] === "webhooks" && match[3] !== undefined)
|
|
1099
|
+
return `${match[2]}:${match[3]}`;
|
|
1100
|
+
return match[2];
|
|
1101
|
+
}
|
|
1102
|
+
function scopeBucket(hashOrRoute, major) {
|
|
1103
|
+
return `${hashOrRoute}|${major}`;
|
|
1104
|
+
}
|
|
872
1105
|
function createRetryPolicy(maxRetries = 2) {
|
|
873
1106
|
if (!Number.isFinite(maxRetries) || maxRetries < 0)
|
|
874
1107
|
throw new TypeError("maxRetries must be a non-negative finite number.");
|
|
@@ -891,14 +1124,21 @@ class REST {
|
|
|
891
1124
|
#timeout;
|
|
892
1125
|
#retryPolicy;
|
|
893
1126
|
#token;
|
|
894
|
-
#
|
|
895
|
-
#
|
|
896
|
-
#
|
|
1127
|
+
#store;
|
|
1128
|
+
#localQueues = new Map;
|
|
1129
|
+
#hooks = {};
|
|
897
1130
|
constructor(options = {}) {
|
|
898
1131
|
this.#token = options.token;
|
|
899
1132
|
this.#timeout = Math.max(1, options.timeout ?? 15000);
|
|
900
1133
|
this.#retryPolicy = options.retryPolicy ?? createRetryPolicy(options.retries ?? 2);
|
|
901
1134
|
this.#baseURL = (options.baseURL ?? "https://discord.com/api/v10").replace(/\/$/, "");
|
|
1135
|
+
this.#store = options.store ?? new MemoryRateLimitStore;
|
|
1136
|
+
if (options.hooks)
|
|
1137
|
+
this.#hooks = options.hooks;
|
|
1138
|
+
}
|
|
1139
|
+
setHooks(hooks) {
|
|
1140
|
+
this.#hooks = hooks;
|
|
1141
|
+
return this;
|
|
902
1142
|
}
|
|
903
1143
|
setToken(token) {
|
|
904
1144
|
if (!token.trim())
|
|
@@ -911,56 +1151,91 @@ class REST {
|
|
|
911
1151
|
throw new TypeError("REST method is required.");
|
|
912
1152
|
if (!path.startsWith("/"))
|
|
913
1153
|
throw new TypeError("REST paths must start with '/'.");
|
|
1154
|
+
const files = options.files;
|
|
1155
|
+
if (files && files.length > 0 && !(body instanceof FormData))
|
|
1156
|
+
body = this.#fileForm(body, files);
|
|
1157
|
+
const query = serializeQuery(options.query);
|
|
1158
|
+
const finalPath = query ? `${path}${query}` : path;
|
|
914
1159
|
const route = `${normalizedMethod}:${this.#normalizeRoute(path)}`;
|
|
915
|
-
|
|
916
|
-
let
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
queue: Promise.resolve()
|
|
920
|
-
};
|
|
921
|
-
this.#buckets.set(bucketKey, bucket);
|
|
922
|
-
const previous = bucket.queue;
|
|
1160
|
+
const major = majorParameter(path);
|
|
1161
|
+
let bucketKey = scopeBucket(await this.#store.getBucketHash(route) ?? route, major);
|
|
1162
|
+
const queueKey = bucketKey;
|
|
1163
|
+
const previous = this.#localQueues.get(queueKey) ?? Promise.resolve();
|
|
923
1164
|
let release;
|
|
924
|
-
|
|
1165
|
+
const gate = new Promise((resolve) => {
|
|
925
1166
|
release = resolve;
|
|
926
1167
|
});
|
|
1168
|
+
this.#localQueues.set(queueKey, gate);
|
|
927
1169
|
await this.#abortable(previous, options.signal, path);
|
|
928
1170
|
try {
|
|
929
1171
|
for (let attempt = 0;attempt <= this.#retryPolicy.maxRetries; attempt++) {
|
|
930
|
-
await this.#wait(
|
|
1172
|
+
await this.#wait(bucketKey, options.signal, path);
|
|
931
1173
|
await this.#waitGlobal(options.signal, path);
|
|
932
1174
|
const controller = new AbortController;
|
|
933
1175
|
const onAbort = () => controller.abort(options.signal?.reason);
|
|
934
1176
|
if (options.signal?.aborted)
|
|
935
1177
|
throw this.#abortError(path, options.signal.reason);
|
|
936
|
-
options.signal?.addEventListener("abort", onAbort, {
|
|
1178
|
+
options.signal?.addEventListener("abort", onAbort, {
|
|
1179
|
+
once: true
|
|
1180
|
+
});
|
|
937
1181
|
const timer = setTimeout(() => controller.abort(new DOMException("REST request timeout", "TimeoutError")), this.#timeout);
|
|
938
1182
|
const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
|
|
939
|
-
const headers = {
|
|
940
|
-
|
|
941
|
-
"
|
|
942
|
-
|
|
1183
|
+
const headers = { ...options.headers };
|
|
1184
|
+
if (options.auth !== false && this.#token)
|
|
1185
|
+
headers["Authorization"] = `Bot ${this.#token}`;
|
|
1186
|
+
headers["User-Agent"] = USER_AGENT;
|
|
1187
|
+
if (options.reason !== undefined)
|
|
1188
|
+
headers["X-Audit-Log-Reason"] = encodeURIComponent(options.reason);
|
|
943
1189
|
if (!isFormData)
|
|
944
1190
|
headers["Content-Type"] = "application/json";
|
|
945
1191
|
const fetchBody = isFormData ? body : body === undefined ? undefined : JSON.stringify(body);
|
|
946
1192
|
try {
|
|
947
|
-
|
|
1193
|
+
this.#emit(this.#hooks.onRequest, {
|
|
1194
|
+
method: normalizedMethod,
|
|
1195
|
+
path,
|
|
1196
|
+
attempt
|
|
1197
|
+
});
|
|
1198
|
+
const requestStart = Date.now();
|
|
1199
|
+
const response = await fetch(`${this.#baseURL}${finalPath}`, {
|
|
948
1200
|
method: normalizedMethod,
|
|
949
1201
|
headers,
|
|
950
1202
|
body: fetchBody,
|
|
951
1203
|
signal: controller.signal
|
|
952
1204
|
});
|
|
953
|
-
|
|
954
|
-
|
|
1205
|
+
this.#emit(this.#hooks.onResponse, {
|
|
1206
|
+
method: normalizedMethod,
|
|
1207
|
+
path,
|
|
1208
|
+
status: response.status,
|
|
1209
|
+
durationMs: Date.now() - requestStart
|
|
1210
|
+
});
|
|
1211
|
+
bucketKey = await this.#update(response, bucketKey, route, major);
|
|
955
1212
|
const payload = await this.#readPayload(response);
|
|
956
1213
|
if (response.ok)
|
|
957
1214
|
return response.status === 204 ? undefined : payload;
|
|
958
1215
|
const data = this.#errorData(payload);
|
|
959
1216
|
const retryAfter = response.status === 429 ? this.#retryAfter(response, data) : undefined;
|
|
960
|
-
if (data.global && retryAfter !== undefined)
|
|
961
|
-
|
|
1217
|
+
if (data.global && retryAfter !== undefined) {
|
|
1218
|
+
const currentGlobal = await this.#store.getGlobalReset();
|
|
1219
|
+
await this.#store.setGlobalReset(Math.max(currentGlobal, Date.now() + retryAfter * 1000));
|
|
1220
|
+
}
|
|
1221
|
+
if (response.status === 429)
|
|
1222
|
+
this.#emit(this.#hooks.onRateLimit, {
|
|
1223
|
+
method: normalizedMethod,
|
|
1224
|
+
path,
|
|
1225
|
+
retryAfterMs: (retryAfter ?? 1) * 1000,
|
|
1226
|
+
global: data.global ?? false,
|
|
1227
|
+
bucket: await this.#store.getBucketHash(route)
|
|
1228
|
+
});
|
|
962
1229
|
if (attempt < this.#retryPolicy.maxRetries && this.#retryPolicy.shouldRetry(normalizedMethod, response.status)) {
|
|
963
|
-
|
|
1230
|
+
const delay = this.#retryPolicy.getDelay(attempt, retryAfter);
|
|
1231
|
+
this.#emit(this.#hooks.onRetry, {
|
|
1232
|
+
method: normalizedMethod,
|
|
1233
|
+
path,
|
|
1234
|
+
attempt,
|
|
1235
|
+
status: response.status,
|
|
1236
|
+
delayMs: delay
|
|
1237
|
+
});
|
|
1238
|
+
await this.#sleep(delay, options.signal, path);
|
|
964
1239
|
continue;
|
|
965
1240
|
}
|
|
966
1241
|
throw new RESTError(data.message ?? response.statusText ?? `Discord REST request failed with status ${response.status}`, response.status, data.code, payload, { method: normalizedMethod, path });
|
|
@@ -983,22 +1258,29 @@ class REST {
|
|
|
983
1258
|
throw new RESTError("Discord REST request exhausted its retry attempts", 0, undefined, undefined, { method: normalizedMethod, path });
|
|
984
1259
|
} finally {
|
|
985
1260
|
release();
|
|
1261
|
+
if (this.#localQueues.get(queueKey) === gate)
|
|
1262
|
+
this.#localQueues.delete(queueKey);
|
|
986
1263
|
}
|
|
987
1264
|
}
|
|
1265
|
+
#dispatch(method, path, bodyOrOptions, options) {
|
|
1266
|
+
if (options === undefined && isRequestData(bodyOrOptions))
|
|
1267
|
+
return this.request(method, path, bodyOrOptions.body, bodyOrOptions);
|
|
1268
|
+
return this.request(method, path, bodyOrOptions, options);
|
|
1269
|
+
}
|
|
988
1270
|
get(path, options) {
|
|
989
|
-
return this.request("GET", path,
|
|
1271
|
+
return this.request("GET", path, options?.body, options);
|
|
990
1272
|
}
|
|
991
1273
|
post(path, body, options) {
|
|
992
|
-
return this
|
|
1274
|
+
return this.#dispatch("POST", path, body, options);
|
|
993
1275
|
}
|
|
994
1276
|
patch(path, body, options) {
|
|
995
|
-
return this
|
|
1277
|
+
return this.#dispatch("PATCH", path, body, options);
|
|
996
1278
|
}
|
|
997
1279
|
put(path, body, options) {
|
|
998
|
-
return this
|
|
1280
|
+
return this.#dispatch("PUT", path, body, options);
|
|
999
1281
|
}
|
|
1000
1282
|
delete(path, options) {
|
|
1001
|
-
return this.request("DELETE", path,
|
|
1283
|
+
return this.request("DELETE", path, options?.body, options);
|
|
1002
1284
|
}
|
|
1003
1285
|
#fileForm(payload, files) {
|
|
1004
1286
|
const form = new FormData;
|
|
@@ -1018,13 +1300,22 @@ class REST {
|
|
|
1018
1300
|
patchWithFiles(path, payload, files, options) {
|
|
1019
1301
|
return this.request("PATCH", path, this.#fileForm(payload, files), options);
|
|
1020
1302
|
}
|
|
1021
|
-
|
|
1303
|
+
#emit(hook, ctx) {
|
|
1304
|
+
if (!hook)
|
|
1305
|
+
return;
|
|
1306
|
+
Promise.resolve().then(() => hook(ctx)).catch(() => {});
|
|
1307
|
+
}
|
|
1308
|
+
async#wait(bucketKey, signal, path) {
|
|
1309
|
+
const bucket = await this.#store.getBucket(bucketKey);
|
|
1310
|
+
if (!bucket)
|
|
1311
|
+
return;
|
|
1022
1312
|
const delay = bucket.resetAt - Date.now();
|
|
1023
1313
|
if (bucket.remaining <= 0 && delay > 0)
|
|
1024
1314
|
await this.#sleep(delay, signal, path);
|
|
1025
1315
|
}
|
|
1026
1316
|
async#waitGlobal(signal, path) {
|
|
1027
|
-
const
|
|
1317
|
+
const globalResetAt = await this.#store.getGlobalReset();
|
|
1318
|
+
const delay = globalResetAt - Date.now();
|
|
1028
1319
|
if (delay > 0)
|
|
1029
1320
|
await this.#sleep(delay, signal, path);
|
|
1030
1321
|
}
|
|
@@ -1088,16 +1379,17 @@ class REST {
|
|
|
1088
1379
|
const routePath = queryIndex === -1 ? path : path.slice(0, queryIndex);
|
|
1089
1380
|
return routePath.replace(/\/\d+(?=\/|$)/g, "/:id");
|
|
1090
1381
|
}
|
|
1091
|
-
#update(response,
|
|
1382
|
+
async#update(response, bucketKey, route, major) {
|
|
1383
|
+
let currentKey = bucketKey;
|
|
1092
1384
|
const serverBucket = response.headers.get("X-RateLimit-Bucket");
|
|
1093
1385
|
if (serverBucket) {
|
|
1094
|
-
this.#
|
|
1095
|
-
|
|
1096
|
-
const shared = this.#buckets.get(serverBucket) ?? bucket;
|
|
1097
|
-
this.#buckets.set(serverBucket, shared);
|
|
1098
|
-
bucket = shared;
|
|
1099
|
-
}
|
|
1386
|
+
await this.#store.setBucketHash(route, serverBucket);
|
|
1387
|
+
currentKey = scopeBucket(serverBucket, major);
|
|
1100
1388
|
}
|
|
1389
|
+
let bucket = await this.#store.getBucket(currentKey) ?? {
|
|
1390
|
+
remaining: 1,
|
|
1391
|
+
resetAt: 0
|
|
1392
|
+
};
|
|
1101
1393
|
const remaining = Number(response.headers.get("X-RateLimit-Remaining"));
|
|
1102
1394
|
const resetAfter = Number(response.headers.get("X-RateLimit-Reset-After"));
|
|
1103
1395
|
const reset = Number(response.headers.get("X-RateLimit-Reset"));
|
|
@@ -1112,12 +1404,15 @@ class REST {
|
|
|
1112
1404
|
if (Number.isFinite(retryAfter))
|
|
1113
1405
|
bucket.resetAt = Math.max(bucket.resetAt, Date.now() + retryAfter * 1000);
|
|
1114
1406
|
}
|
|
1407
|
+
await this.#store.updateBucket(currentKey, bucket);
|
|
1115
1408
|
if (response.headers.get("X-RateLimit-Global") === "true") {
|
|
1116
1409
|
const retryAfter = Number(response.headers.get("Retry-After"));
|
|
1117
|
-
if (Number.isFinite(retryAfter))
|
|
1118
|
-
|
|
1410
|
+
if (Number.isFinite(retryAfter)) {
|
|
1411
|
+
const currentGlobal = await this.#store.getGlobalReset();
|
|
1412
|
+
await this.#store.setGlobalReset(Math.max(currentGlobal, Date.now() + retryAfter * 1000));
|
|
1413
|
+
}
|
|
1119
1414
|
}
|
|
1120
|
-
return
|
|
1415
|
+
return currentKey;
|
|
1121
1416
|
}
|
|
1122
1417
|
}
|
|
1123
1418
|
|
|
@@ -1263,6 +1558,13 @@ class Guild extends BaseStructure {
|
|
|
1263
1558
|
vanityUrlCode;
|
|
1264
1559
|
nsfwLevel;
|
|
1265
1560
|
discoverySplash;
|
|
1561
|
+
rulesChannelId;
|
|
1562
|
+
systemChannelId;
|
|
1563
|
+
systemChannelFlags;
|
|
1564
|
+
maxMembers;
|
|
1565
|
+
mfaLevel;
|
|
1566
|
+
explicitContentFilter;
|
|
1567
|
+
defaultMessageNotifications;
|
|
1266
1568
|
constructor(data) {
|
|
1267
1569
|
super(data.id);
|
|
1268
1570
|
if (!data.name)
|
|
@@ -1284,6 +1586,14 @@ class Guild extends BaseStructure {
|
|
|
1284
1586
|
this.vanityUrlCode = data.vanity_url_code ?? null;
|
|
1285
1587
|
this.nsfwLevel = data.nsfw_level ?? 0;
|
|
1286
1588
|
this.discoverySplash = data.discovery_splash ?? null;
|
|
1589
|
+
const d = data;
|
|
1590
|
+
this.rulesChannelId = d.rules_channel_id ?? null;
|
|
1591
|
+
this.systemChannelId = d.system_channel_id ?? null;
|
|
1592
|
+
this.systemChannelFlags = d.system_channel_flags ?? 0;
|
|
1593
|
+
this.maxMembers = d.max_members ?? 0;
|
|
1594
|
+
this.mfaLevel = d.mfa_level ?? 0;
|
|
1595
|
+
this.explicitContentFilter = d.explicit_content_filter ?? 0;
|
|
1596
|
+
this.defaultMessageNotifications = d.default_message_notifications ?? 0;
|
|
1287
1597
|
}
|
|
1288
1598
|
iconURL(options = {}) {
|
|
1289
1599
|
if (!this.icon)
|
|
@@ -1305,12 +1615,27 @@ class Guild extends BaseStructure {
|
|
|
1305
1615
|
return null;
|
|
1306
1616
|
return cdnURL(`/discovery-splashes/${this.id}`, this.discoverySplash, options);
|
|
1307
1617
|
}
|
|
1618
|
+
widgetImageURL(style = "shield") {
|
|
1619
|
+
return `https://discord.com/api/guilds/${this.id}/widget.png?style=${style}`;
|
|
1620
|
+
}
|
|
1308
1621
|
hasFeature(feature) {
|
|
1309
1622
|
return this.features.includes(feature);
|
|
1310
1623
|
}
|
|
1311
1624
|
get isCommunity() {
|
|
1312
1625
|
return this.hasFeature("COMMUNITY");
|
|
1313
1626
|
}
|
|
1627
|
+
get isPartnered() {
|
|
1628
|
+
return this.hasFeature("PARTNERED");
|
|
1629
|
+
}
|
|
1630
|
+
get isVerified() {
|
|
1631
|
+
return this.hasFeature("VERIFIED");
|
|
1632
|
+
}
|
|
1633
|
+
get isBoosted() {
|
|
1634
|
+
return this.premiumSubscriptionCount > 0;
|
|
1635
|
+
}
|
|
1636
|
+
get boostLevel() {
|
|
1637
|
+
return this.premiumTier;
|
|
1638
|
+
}
|
|
1314
1639
|
get hasVanityUrl() {
|
|
1315
1640
|
return this.vanityUrlCode !== null;
|
|
1316
1641
|
}
|
|
@@ -1321,58 +1646,49 @@ class Guild extends BaseStructure {
|
|
|
1321
1646
|
return this.name;
|
|
1322
1647
|
}
|
|
1323
1648
|
}
|
|
1324
|
-
// packages/structures/src/
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
ViewCreatorMonetizationAnalytics: 1n << 41n,
|
|
1368
|
-
UseSoundboard: 1n << 42n,
|
|
1369
|
-
CreateGuildExpressions: 1n << 43n,
|
|
1370
|
-
CreateEvents: 1n << 44n,
|
|
1371
|
-
UseExternalSounds: 1n << 45n,
|
|
1372
|
-
SendVoiceMessages: 1n << 46n,
|
|
1373
|
-
SendPolls: 1n << 49n,
|
|
1374
|
-
UseExternalApps: 1n << 50n
|
|
1375
|
-
};
|
|
1649
|
+
// packages/structures/src/resources.ts
|
|
1650
|
+
class AutoModerationRule extends BaseStructure {
|
|
1651
|
+
guildId;
|
|
1652
|
+
name;
|
|
1653
|
+
creatorId;
|
|
1654
|
+
eventType;
|
|
1655
|
+
triggerType;
|
|
1656
|
+
triggerMetadata;
|
|
1657
|
+
actions;
|
|
1658
|
+
enabled;
|
|
1659
|
+
exemptRoles;
|
|
1660
|
+
exemptChannels;
|
|
1661
|
+
constructor(data) {
|
|
1662
|
+
super(data.id);
|
|
1663
|
+
if (!/^\d{1,20}$/.test(data.guild_id))
|
|
1664
|
+
throw new TypeError("AutoModerationRule guild_id must be a valid snowflake.");
|
|
1665
|
+
this.guildId = data.guild_id;
|
|
1666
|
+
this.name = data.name;
|
|
1667
|
+
this.creatorId = data.creator_id;
|
|
1668
|
+
this.eventType = data.event_type;
|
|
1669
|
+
this.triggerType = data.trigger_type;
|
|
1670
|
+
this.triggerMetadata = data.trigger_metadata;
|
|
1671
|
+
this.actions = data.actions;
|
|
1672
|
+
this.enabled = data.enabled;
|
|
1673
|
+
this.exemptRoles = data.exempt_roles;
|
|
1674
|
+
this.exemptChannels = data.exempt_channels;
|
|
1675
|
+
}
|
|
1676
|
+
toJSON() {
|
|
1677
|
+
return {
|
|
1678
|
+
id: this.id,
|
|
1679
|
+
guildId: this.guildId,
|
|
1680
|
+
name: this.name,
|
|
1681
|
+
creatorId: this.creatorId,
|
|
1682
|
+
eventType: this.eventType,
|
|
1683
|
+
triggerType: this.triggerType,
|
|
1684
|
+
triggerMetadata: this.triggerMetadata,
|
|
1685
|
+
actions: this.actions,
|
|
1686
|
+
enabled: this.enabled,
|
|
1687
|
+
exemptRoles: this.exemptRoles,
|
|
1688
|
+
exemptChannels: this.exemptChannels
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1376
1692
|
// packages/structures/src/interactions.ts
|
|
1377
1693
|
var InteractionType = {
|
|
1378
1694
|
Ping: 1,
|
|
@@ -1663,8 +1979,7 @@ class CommandInteraction extends Interaction {
|
|
|
1663
1979
|
super(client, data);
|
|
1664
1980
|
const rawOptions = data.data?.options ?? [];
|
|
1665
1981
|
const resolved = data.data?.resolved ?? {};
|
|
1666
|
-
|
|
1667
|
-
this.options = new CommandOptions(sub?.options ?? rawOptions, resolved);
|
|
1982
|
+
this.options = new CommandOptions(rawOptions, resolved);
|
|
1668
1983
|
}
|
|
1669
1984
|
}
|
|
1670
1985
|
|
|
@@ -1758,6 +2073,8 @@ function createInteraction(client, data) {
|
|
|
1758
2073
|
}
|
|
1759
2074
|
|
|
1760
2075
|
// packages/structures/src/index.ts
|
|
2076
|
+
var NON_SYSTEM_MESSAGE_TYPES = new Set([0, 19, 20, 23]);
|
|
2077
|
+
|
|
1761
2078
|
class Message extends BaseStructure {
|
|
1762
2079
|
content;
|
|
1763
2080
|
author;
|
|
@@ -1803,6 +2120,12 @@ class Message extends BaseStructure {
|
|
|
1803
2120
|
get embedsSuppressed() {
|
|
1804
2121
|
return (this.flags & 4) !== 0;
|
|
1805
2122
|
}
|
|
2123
|
+
get createdTimestamp() {
|
|
2124
|
+
return this.timestamp.getTime();
|
|
2125
|
+
}
|
|
2126
|
+
get createdAt() {
|
|
2127
|
+
return this.timestamp;
|
|
2128
|
+
}
|
|
1806
2129
|
edit(options) {
|
|
1807
2130
|
if (!this.#context)
|
|
1808
2131
|
throw new Error("This message is not attached to a client.");
|
|
@@ -1857,6 +2180,51 @@ class Message extends BaseStructure {
|
|
|
1857
2180
|
throw new Error("This message is not attached to a client.");
|
|
1858
2181
|
return this.#context.unpinMessage(this.channelId, this.id);
|
|
1859
2182
|
}
|
|
2183
|
+
get isEphemeral() {
|
|
2184
|
+
return (this.flags & 64) !== 0;
|
|
2185
|
+
}
|
|
2186
|
+
get isPinned() {
|
|
2187
|
+
return this.pinned;
|
|
2188
|
+
}
|
|
2189
|
+
get isSystemMessage() {
|
|
2190
|
+
return !NON_SYSTEM_MESSAGE_TYPES.has(this.type);
|
|
2191
|
+
}
|
|
2192
|
+
get isCrosspost() {
|
|
2193
|
+
return (this.flags & 2) !== 0;
|
|
2194
|
+
}
|
|
2195
|
+
get hasAttachments() {
|
|
2196
|
+
return this.attachments.length > 0;
|
|
2197
|
+
}
|
|
2198
|
+
get hasEmbeds() {
|
|
2199
|
+
return this.embeds.length > 0;
|
|
2200
|
+
}
|
|
2201
|
+
get hasComponents() {
|
|
2202
|
+
return this.components.length > 0;
|
|
2203
|
+
}
|
|
2204
|
+
suppressEmbeds() {
|
|
2205
|
+
return this.edit({ flags: this.flags | 4 });
|
|
2206
|
+
}
|
|
2207
|
+
toJSON() {
|
|
2208
|
+
return {
|
|
2209
|
+
id: this.id,
|
|
2210
|
+
content: this.content,
|
|
2211
|
+
channelId: this.channelId,
|
|
2212
|
+
guildId: this.guildId,
|
|
2213
|
+
flags: this.flags,
|
|
2214
|
+
pinned: this.pinned,
|
|
2215
|
+
mentionEveryone: this.mentionEveryone,
|
|
2216
|
+
type: this.type,
|
|
2217
|
+
timestamp: this.timestamp.toISOString(),
|
|
2218
|
+
author: { id: this.author.id, username: this.author.username },
|
|
2219
|
+
attachments: [...this.attachments],
|
|
2220
|
+
embeds: [...this.embeds],
|
|
2221
|
+
components: [...this.components],
|
|
2222
|
+
mentions: this.mentions.map((u) => u.id),
|
|
2223
|
+
mentionRoles: [...this.mentionRoles],
|
|
2224
|
+
reference: this.reference,
|
|
2225
|
+
referencedMessage: this.referencedMessage ? this.referencedMessage.id : this.referencedMessage
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
1860
2228
|
}
|
|
1861
2229
|
|
|
1862
2230
|
// packages/managers/src/message.ts
|
|
@@ -1948,6 +2316,11 @@ class UserManager extends ResourceManager {
|
|
|
1948
2316
|
}
|
|
1949
2317
|
}
|
|
1950
2318
|
// packages/managers/src/guild.ts
|
|
2319
|
+
function withQuery(path, params) {
|
|
2320
|
+
const suffix = params.toString();
|
|
2321
|
+
return suffix ? `${path}?${suffix}` : path;
|
|
2322
|
+
}
|
|
2323
|
+
|
|
1951
2324
|
class GuildManager extends ResourceManager {
|
|
1952
2325
|
#rest;
|
|
1953
2326
|
constructor(rest) {
|
|
@@ -1977,6 +2350,47 @@ class GuildManager extends ResourceManager {
|
|
|
1977
2350
|
async fetchInvites(id) {
|
|
1978
2351
|
return this.#rest.get(Routes.guildInvites(id));
|
|
1979
2352
|
}
|
|
2353
|
+
async fetchAuditLog(guildId, options = {}) {
|
|
2354
|
+
const params = new URLSearchParams;
|
|
2355
|
+
if (options.userId)
|
|
2356
|
+
params.set("user_id", options.userId);
|
|
2357
|
+
if (options.actionType !== undefined)
|
|
2358
|
+
params.set("action_type", String(options.actionType));
|
|
2359
|
+
if (options.before)
|
|
2360
|
+
params.set("before", options.before);
|
|
2361
|
+
if (options.after)
|
|
2362
|
+
params.set("after", options.after);
|
|
2363
|
+
if (options.limit !== undefined)
|
|
2364
|
+
params.set("limit", String(Math.min(100, Math.max(1, options.limit))));
|
|
2365
|
+
return this.#rest.get(withQuery(Routes.guildAuditLog(guildId), params));
|
|
2366
|
+
}
|
|
2367
|
+
async fetchMembers(guildId, options = {}) {
|
|
2368
|
+
const params = new URLSearchParams;
|
|
2369
|
+
if (options.limit !== undefined)
|
|
2370
|
+
params.set("limit", String(Math.min(1000, Math.max(1, options.limit))));
|
|
2371
|
+
if (options.after)
|
|
2372
|
+
params.set("after", options.after);
|
|
2373
|
+
return this.#rest.get(withQuery(Routes.guildMembers(guildId), params));
|
|
2374
|
+
}
|
|
2375
|
+
async fetchAutoModerationRules(guildId) {
|
|
2376
|
+
const rules = await this.#rest.get(Routes.guildAutoModerationRules(guildId));
|
|
2377
|
+
return rules.map((r) => new AutoModerationRule(r));
|
|
2378
|
+
}
|
|
2379
|
+
async fetchAutoModerationRule(guildId, ruleId) {
|
|
2380
|
+
const rule = await this.#rest.get(Routes.guildAutoModerationRule(guildId, ruleId));
|
|
2381
|
+
return new AutoModerationRule(rule);
|
|
2382
|
+
}
|
|
2383
|
+
async createAutoModerationRule(guildId, options) {
|
|
2384
|
+
const rule = await this.#rest.post(Routes.guildAutoModerationRules(guildId), options);
|
|
2385
|
+
return new AutoModerationRule(rule);
|
|
2386
|
+
}
|
|
2387
|
+
async editAutoModerationRule(guildId, ruleId, options) {
|
|
2388
|
+
const rule = await this.#rest.patch(Routes.guildAutoModerationRule(guildId, ruleId), options);
|
|
2389
|
+
return new AutoModerationRule(rule);
|
|
2390
|
+
}
|
|
2391
|
+
async deleteAutoModerationRule(guildId, ruleId) {
|
|
2392
|
+
await this.#rest.delete(Routes.guildAutoModerationRule(guildId, ruleId));
|
|
2393
|
+
}
|
|
1980
2394
|
}
|
|
1981
2395
|
// packages/managers/src/application.ts
|
|
1982
2396
|
class ApplicationCommandManager {
|
|
@@ -2079,8 +2493,11 @@ class ChannelManager extends Manager {
|
|
|
2079
2493
|
}
|
|
2080
2494
|
async deleteChannel(channelId) {
|
|
2081
2495
|
await this.#rest.delete(Routes.channel(channelId));
|
|
2496
|
+
this.delete(channelId);
|
|
2497
|
+
}
|
|
2498
|
+
delete(channelId) {
|
|
2082
2499
|
this.#messageManagers.delete(channelId);
|
|
2083
|
-
super.delete(channelId);
|
|
2500
|
+
return super.delete(channelId);
|
|
2084
2501
|
}
|
|
2085
2502
|
send(channelId, options) {
|
|
2086
2503
|
return this.messages(channelId).send(options);
|
|
@@ -2125,6 +2542,8 @@ class ChannelManager extends Manager {
|
|
|
2125
2542
|
}
|
|
2126
2543
|
async bulkDeleteMessages(channelId, messageIds) {
|
|
2127
2544
|
const ids = [...messageIds];
|
|
2545
|
+
if (ids.length < 2 || ids.length > 100)
|
|
2546
|
+
throw new RangeError("bulkDelete requires between 2 and 100 message IDs.");
|
|
2128
2547
|
await this.#rest.post(Routes.channelBulkDelete(channelId), {
|
|
2129
2548
|
messages: ids
|
|
2130
2549
|
});
|
|
@@ -2132,7 +2551,7 @@ class ChannelManager extends Manager {
|
|
|
2132
2551
|
this.messages(channelId).delete(id);
|
|
2133
2552
|
}
|
|
2134
2553
|
async addReaction(channelId, messageId, emoji) {
|
|
2135
|
-
await this.#rest.put(Routes.messageReactions(channelId, messageId, emoji));
|
|
2554
|
+
await this.#rest.put(`${Routes.messageReactions(channelId, messageId, emoji)}/@me`);
|
|
2136
2555
|
}
|
|
2137
2556
|
async fetchReactions(channelId, messageId, emoji, options = {}) {
|
|
2138
2557
|
const params = new URLSearchParams;
|
|
@@ -2166,9 +2585,21 @@ class ChannelManager extends Manager {
|
|
|
2166
2585
|
createThreadFromMessage(channelId, messageId, options) {
|
|
2167
2586
|
return this.threads(channelId).createFromMessage(messageId, options);
|
|
2168
2587
|
}
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2588
|
+
async fetchPage(channelId, options = {}) {
|
|
2589
|
+
const limit = Math.min(100, Math.max(1, options.limit ?? 50));
|
|
2590
|
+
const messages = await this.fetchMessages(channelId, {
|
|
2591
|
+
...options,
|
|
2592
|
+
limit
|
|
2593
|
+
});
|
|
2594
|
+
return {
|
|
2595
|
+
messages,
|
|
2596
|
+
before: messages[0]?.id,
|
|
2597
|
+
after: messages[messages.length - 1]?.id,
|
|
2598
|
+
hasMore: messages.length === limit
|
|
2599
|
+
};
|
|
2600
|
+
}
|
|
2601
|
+
async bulkDelete(channelId, messageIds) {
|
|
2602
|
+
return this.bulkDeleteMessages(channelId, messageIds);
|
|
2172
2603
|
}
|
|
2173
2604
|
clear() {
|
|
2174
2605
|
this.#messageManagers.clear();
|
|
@@ -2193,6 +2624,22 @@ var GatewayOpcodes = {
|
|
|
2193
2624
|
Hello: 10,
|
|
2194
2625
|
HeartbeatAck: 11
|
|
2195
2626
|
};
|
|
2627
|
+
var GatewayCloseCodes = {
|
|
2628
|
+
UnknownError: 4000,
|
|
2629
|
+
UnknownOpcode: 4001,
|
|
2630
|
+
DecodeError: 4002,
|
|
2631
|
+
NotAuthenticated: 4003,
|
|
2632
|
+
AuthenticationFailed: 4004,
|
|
2633
|
+
AlreadyAuthenticated: 4005,
|
|
2634
|
+
InvalidSeq: 4007,
|
|
2635
|
+
RateLimited: 4008,
|
|
2636
|
+
SessionTimedOut: 4009,
|
|
2637
|
+
InvalidShard: 4010,
|
|
2638
|
+
ShardingRequired: 4011,
|
|
2639
|
+
InvalidAPIVersion: 4012,
|
|
2640
|
+
InvalidIntents: 4013,
|
|
2641
|
+
DisallowedIntents: 4014
|
|
2642
|
+
};
|
|
2196
2643
|
class GatewayError extends Error {
|
|
2197
2644
|
code;
|
|
2198
2645
|
constructor(message, code, options) {
|
|
@@ -2226,6 +2673,8 @@ class Gateway {
|
|
|
2226
2673
|
#rejectConnect;
|
|
2227
2674
|
#listeners = new Map;
|
|
2228
2675
|
#sendTimestamps = [];
|
|
2676
|
+
ping = -1;
|
|
2677
|
+
#decompressor;
|
|
2229
2678
|
constructor(options) {
|
|
2230
2679
|
if (!options.token?.trim())
|
|
2231
2680
|
throw new TypeError("A Gateway token is required.");
|
|
@@ -2246,7 +2695,12 @@ class Gateway {
|
|
|
2246
2695
|
browser: "Discord Android",
|
|
2247
2696
|
device: "Discord Android"
|
|
2248
2697
|
},
|
|
2249
|
-
presence: {
|
|
2698
|
+
presence: {
|
|
2699
|
+
status: "online",
|
|
2700
|
+
activities: [],
|
|
2701
|
+
afk: false,
|
|
2702
|
+
since: null
|
|
2703
|
+
},
|
|
2250
2704
|
...options
|
|
2251
2705
|
};
|
|
2252
2706
|
if (this.#options.shardId < 0 || this.#options.shardId >= this.#options.shardCount)
|
|
@@ -2261,10 +2715,13 @@ class Gateway {
|
|
|
2261
2715
|
return this.#connectPromise;
|
|
2262
2716
|
this.#closed = false;
|
|
2263
2717
|
this.#setState("CONNECT" /* Connect */);
|
|
2718
|
+
const connectURL = this.#options.compress ? url.includes("compress=") ? url : `${url}&compress=zlib-stream` : url;
|
|
2719
|
+
if (this.#options.compress)
|
|
2720
|
+
this.#initDecompressor();
|
|
2264
2721
|
this.#connectPromise = new Promise((resolve, reject) => {
|
|
2265
2722
|
this.#resolveConnect = resolve;
|
|
2266
2723
|
this.#rejectConnect = reject;
|
|
2267
|
-
this.#open(
|
|
2724
|
+
this.#open(connectURL);
|
|
2268
2725
|
});
|
|
2269
2726
|
return this.#connectPromise;
|
|
2270
2727
|
}
|
|
@@ -2300,12 +2757,15 @@ class Gateway {
|
|
|
2300
2757
|
send(payload) {
|
|
2301
2758
|
if (!payload || !Number.isInteger(payload.op))
|
|
2302
2759
|
throw new TypeError("Gateway payload must contain an integer opcode.");
|
|
2760
|
+
return this.#dispatch(payload, false);
|
|
2761
|
+
}
|
|
2762
|
+
#dispatch(payload, privileged) {
|
|
2303
2763
|
if (this.#ws?.readyState !== WebSocket.OPEN)
|
|
2304
2764
|
return false;
|
|
2305
2765
|
const now = Date.now();
|
|
2306
2766
|
while (this.#sendTimestamps.length && now - this.#sendTimestamps[0] >= 60000)
|
|
2307
2767
|
this.#sendTimestamps.shift();
|
|
2308
|
-
if (this.#sendTimestamps.length >= 115) {
|
|
2768
|
+
if (!privileged && this.#sendTimestamps.length >= 115) {
|
|
2309
2769
|
this.#emitError(new GatewayError("Gateway send rate budget exhausted."));
|
|
2310
2770
|
return false;
|
|
2311
2771
|
}
|
|
@@ -2376,7 +2836,11 @@ class Gateway {
|
|
|
2376
2836
|
ws.addEventListener("message", (event) => {
|
|
2377
2837
|
this.#lastMessageAt = Date.now();
|
|
2378
2838
|
this.#zombieReported = false;
|
|
2379
|
-
this.#
|
|
2839
|
+
if (this.#options.compress && event.data instanceof ArrayBuffer) {
|
|
2840
|
+
this.#decompress(new Uint8Array(event.data)).then((text) => this.#message(ws, text)).catch((err) => this.#emitError(err));
|
|
2841
|
+
} else {
|
|
2842
|
+
this.#message(ws, String(event.data));
|
|
2843
|
+
}
|
|
2380
2844
|
});
|
|
2381
2845
|
ws.addEventListener("close", (event) => this.#close(ws, event.code));
|
|
2382
2846
|
ws.addEventListener("error", () => this.#emitError(new GatewayError("Gateway WebSocket error")));
|
|
@@ -2384,7 +2848,7 @@ class Gateway {
|
|
|
2384
2848
|
#startZombieDetection() {
|
|
2385
2849
|
if (this.#zombieTimer)
|
|
2386
2850
|
clearInterval(this.#zombieTimer);
|
|
2387
|
-
const interval = Math.max(1, Math.min(
|
|
2851
|
+
const interval = Math.max(1, Math.min(1000, this.#options.heartbeatAckTimeout, this.#options.zombieTimeout / 2));
|
|
2388
2852
|
this.#zombieTimer = setInterval(() => {
|
|
2389
2853
|
if (this.#closed || this.#ws?.readyState !== WebSocket.OPEN || this.#lastMessageAt === 0)
|
|
2390
2854
|
return;
|
|
@@ -2435,18 +2899,24 @@ class Gateway {
|
|
|
2435
2899
|
break;
|
|
2436
2900
|
case GatewayOpcodes.HeartbeatAck:
|
|
2437
2901
|
this.#heartbeatACK = true;
|
|
2902
|
+
this.ping = Date.now() - this.#heartbeatSentAt;
|
|
2438
2903
|
this.#clearHeartbeatAckTimer();
|
|
2439
2904
|
this.#emit("heartbeatAck", payload.d);
|
|
2440
2905
|
break;
|
|
2441
2906
|
case GatewayOpcodes.Reconnect:
|
|
2442
2907
|
ws.close(1001, "Server requested reconnect");
|
|
2443
2908
|
break;
|
|
2444
|
-
case GatewayOpcodes.InvalidSession:
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2909
|
+
case GatewayOpcodes.InvalidSession: {
|
|
2910
|
+
const resumable = payload.d === true;
|
|
2911
|
+
if (!resumable) {
|
|
2912
|
+
this.#sessionId = undefined;
|
|
2913
|
+
this.#sequence = null;
|
|
2914
|
+
this.#resumeURL = undefined;
|
|
2915
|
+
}
|
|
2916
|
+
this.#emit("invalidSession", resumable);
|
|
2917
|
+
ws.close(resumable ? GatewayCloseCodes.UnknownError : 1000, resumable ? "Invalid session (resumable)" : "Invalid session");
|
|
2449
2918
|
break;
|
|
2919
|
+
}
|
|
2450
2920
|
}
|
|
2451
2921
|
}
|
|
2452
2922
|
#handleDispatch(event, data) {
|
|
@@ -2461,6 +2931,10 @@ class Gateway {
|
|
|
2461
2931
|
this.#attempt = 0;
|
|
2462
2932
|
this.#setState("READY" /* Ready */);
|
|
2463
2933
|
this.#emit("ready", data);
|
|
2934
|
+
} else if (event === "RESUMED") {
|
|
2935
|
+
this.#attempt = 0;
|
|
2936
|
+
this.#setState("READY" /* Ready */);
|
|
2937
|
+
this.#emit("resumed", data);
|
|
2464
2938
|
}
|
|
2465
2939
|
this.#emit("RAW", { event: event ?? "UNKNOWN", data });
|
|
2466
2940
|
if (this.#closed)
|
|
@@ -2538,12 +3012,12 @@ class Gateway {
|
|
|
2538
3012
|
#sendHeartbeat() {
|
|
2539
3013
|
this.#heartbeatACK = false;
|
|
2540
3014
|
this.#heartbeatSentAt = Date.now();
|
|
2541
|
-
if (!this
|
|
3015
|
+
if (!this.#dispatch({
|
|
2542
3016
|
op: GatewayOpcodes.Heartbeat,
|
|
2543
3017
|
d: this.#sequence,
|
|
2544
3018
|
s: null,
|
|
2545
3019
|
t: null
|
|
2546
|
-
})) {
|
|
3020
|
+
}, true)) {
|
|
2547
3021
|
this.#emitError(new GatewayError("Unable to send Gateway heartbeat because the WebSocket is not open."));
|
|
2548
3022
|
return;
|
|
2549
3023
|
}
|
|
@@ -2576,14 +3050,23 @@ class Gateway {
|
|
|
2576
3050
|
if (action === "identify") {
|
|
2577
3051
|
this.#sequence = null;
|
|
2578
3052
|
this.#sessionId = undefined;
|
|
3053
|
+
this.#resumeURL = undefined;
|
|
2579
3054
|
}
|
|
2580
3055
|
this.#setState("RECONNECT" /* Reconnect */);
|
|
2581
3056
|
this.#scheduleReconnect();
|
|
2582
3057
|
}
|
|
2583
3058
|
#closeAction(code) {
|
|
2584
|
-
|
|
3059
|
+
const fatal = [
|
|
3060
|
+
GatewayCloseCodes.AuthenticationFailed,
|
|
3061
|
+
GatewayCloseCodes.InvalidShard,
|
|
3062
|
+
GatewayCloseCodes.ShardingRequired,
|
|
3063
|
+
GatewayCloseCodes.InvalidAPIVersion,
|
|
3064
|
+
GatewayCloseCodes.InvalidIntents,
|
|
3065
|
+
GatewayCloseCodes.DisallowedIntents
|
|
3066
|
+
];
|
|
3067
|
+
if (fatal.includes(code))
|
|
2585
3068
|
return "stop";
|
|
2586
|
-
if (
|
|
3069
|
+
if (code === GatewayCloseCodes.InvalidSeq || code === GatewayCloseCodes.SessionTimedOut)
|
|
2587
3070
|
return "identify";
|
|
2588
3071
|
return this.#sessionId && this.#sequence !== null ? "resume" : "identify";
|
|
2589
3072
|
}
|
|
@@ -2596,7 +3079,7 @@ class Gateway {
|
|
|
2596
3079
|
return;
|
|
2597
3080
|
}
|
|
2598
3081
|
const delay = Math.min(this.#options.reconnectMaxDelay, this.#options.reconnectBaseDelay * 2 ** this.#attempt++);
|
|
2599
|
-
const jitter = Math.random() * Math.
|
|
3082
|
+
const jitter = Math.random() * Math.max(1, delay * 0.25);
|
|
2600
3083
|
this.#reconnectTimer = setTimeout(() => {
|
|
2601
3084
|
this.#reconnectTimer = undefined;
|
|
2602
3085
|
this.#open(this.#resumeURL ?? "wss://gateway.discord.gg/?v=10&encoding=json");
|
|
@@ -2666,10 +3149,41 @@ class Gateway {
|
|
|
2666
3149
|
this.state = next;
|
|
2667
3150
|
this.#emit("stateChange", { previous, next });
|
|
2668
3151
|
}
|
|
3152
|
+
#initDecompressor() {
|
|
3153
|
+
const ds = new DecompressionStream("deflate-raw");
|
|
3154
|
+
this.#decompressor = {
|
|
3155
|
+
writer: ds.writable.getWriter(),
|
|
3156
|
+
reader: ds.readable.getReader()
|
|
3157
|
+
};
|
|
3158
|
+
}
|
|
3159
|
+
async#decompress(chunk) {
|
|
3160
|
+
if (!this.#decompressor)
|
|
3161
|
+
this.#initDecompressor();
|
|
3162
|
+
const { writer, reader } = this.#decompressor;
|
|
3163
|
+
await writer.write(chunk);
|
|
3164
|
+
const parts = [];
|
|
3165
|
+
while (true) {
|
|
3166
|
+
const { done, value } = await Promise.race([
|
|
3167
|
+
reader.read(),
|
|
3168
|
+
new Promise((resolve) => setTimeout(() => resolve({ done: true, value: undefined }), 50))
|
|
3169
|
+
]);
|
|
3170
|
+
if (done || !value)
|
|
3171
|
+
break;
|
|
3172
|
+
parts.push(value);
|
|
3173
|
+
}
|
|
3174
|
+
const total = parts.reduce((n, p) => n + p.length, 0);
|
|
3175
|
+
const merged = new Uint8Array(total);
|
|
3176
|
+
let offset = 0;
|
|
3177
|
+
for (const p of parts) {
|
|
3178
|
+
merged.set(p, offset);
|
|
3179
|
+
offset += p.length;
|
|
3180
|
+
}
|
|
3181
|
+
return new TextDecoder().decode(merged);
|
|
3182
|
+
}
|
|
2669
3183
|
}
|
|
2670
3184
|
|
|
2671
3185
|
// packages/core/src/index.ts
|
|
2672
|
-
class
|
|
3186
|
+
class EventEmitter2 {
|
|
2673
3187
|
#listeners = new Map;
|
|
2674
3188
|
on(event, listener) {
|
|
2675
3189
|
if (typeof listener !== "function")
|
|
@@ -2691,6 +3205,9 @@ class EventEmitter {
|
|
|
2691
3205
|
this.#listeners.get(event)?.delete(listener);
|
|
2692
3206
|
return this;
|
|
2693
3207
|
}
|
|
3208
|
+
removeListener(event, listener) {
|
|
3209
|
+
return this.off(event, listener);
|
|
3210
|
+
}
|
|
2694
3211
|
removeAllListeners(event) {
|
|
2695
3212
|
if (event === undefined)
|
|
2696
3213
|
this.#listeners.clear();
|
|
@@ -2727,7 +3244,7 @@ class EventEmitter {
|
|
|
2727
3244
|
}
|
|
2728
3245
|
}
|
|
2729
3246
|
|
|
2730
|
-
class Client extends
|
|
3247
|
+
class Client extends EventEmitter2 {
|
|
2731
3248
|
options;
|
|
2732
3249
|
rest;
|
|
2733
3250
|
users;
|
|
@@ -2743,14 +3260,26 @@ class Client extends EventEmitter {
|
|
|
2743
3260
|
user;
|
|
2744
3261
|
readyAt;
|
|
2745
3262
|
state = "idle";
|
|
3263
|
+
get token() {
|
|
3264
|
+
return this.state === "destroyed" ? null : this.options.token ?? null;
|
|
3265
|
+
}
|
|
2746
3266
|
get uptime() {
|
|
2747
3267
|
return this.readyAt ? Date.now() - this.readyAt.getTime() : null;
|
|
2748
3268
|
}
|
|
3269
|
+
get ping() {
|
|
3270
|
+
return this.#gateway.ping;
|
|
3271
|
+
}
|
|
2749
3272
|
isReady() {
|
|
2750
3273
|
return this.state === "ready";
|
|
2751
3274
|
}
|
|
2752
3275
|
setPresence(data) {
|
|
2753
|
-
return this.#gateway.setPresence
|
|
3276
|
+
return this.#gateway.setPresence(data);
|
|
3277
|
+
}
|
|
3278
|
+
setVoiceState(data) {
|
|
3279
|
+
return this.#gateway.setVoiceState(data);
|
|
3280
|
+
}
|
|
3281
|
+
requestGuildMembers(data) {
|
|
3282
|
+
return this.#gateway.requestGuildMembers(data);
|
|
2754
3283
|
}
|
|
2755
3284
|
#gateway;
|
|
2756
3285
|
#resourceContext;
|
|
@@ -2794,6 +3323,13 @@ class Client extends EventEmitter {
|
|
|
2794
3323
|
this.application.commands = new ApplicationCommandManager(this.rest, appId);
|
|
2795
3324
|
this.emit("ready" /* Ready */, this.user);
|
|
2796
3325
|
});
|
|
3326
|
+
this.#gateway.on("RESUMED", () => {
|
|
3327
|
+
this.state = "ready";
|
|
3328
|
+
this.emit("resumed" /* Resumed */);
|
|
3329
|
+
});
|
|
3330
|
+
this.#gateway.on("invalidSession", (isRecoverable) => {
|
|
3331
|
+
this.emit("invalidSession" /* InvalidSession */, isRecoverable);
|
|
3332
|
+
});
|
|
2797
3333
|
this.#gateway.on("open", () => this.emit("open" /* Open */));
|
|
2798
3334
|
this.#gateway.on("close", (data) => {
|
|
2799
3335
|
if (this.state !== "destroyed")
|
|
@@ -2826,6 +3362,7 @@ class Client extends EventEmitter {
|
|
|
2826
3362
|
this.emit("guildUnavailable" /* GuildUnavailable */, payload);
|
|
2827
3363
|
return;
|
|
2828
3364
|
}
|
|
3365
|
+
const wasCached = this.guilds.has(payload.id);
|
|
2829
3366
|
const guild = new Guild(payload);
|
|
2830
3367
|
this.guilds.set(guild.id, guild);
|
|
2831
3368
|
for (const member of payload.members ?? [])
|
|
@@ -2835,7 +3372,7 @@ class Client extends EventEmitter {
|
|
|
2835
3372
|
...payload.threads ?? []
|
|
2836
3373
|
])
|
|
2837
3374
|
this.channels.set(channelData.id, new Channel(channelData, this.#resourceContext));
|
|
2838
|
-
this.emit("guildCreate" /* GuildCreate */, payload);
|
|
3375
|
+
this.emit(wasCached ? "guildAvailable" /* GuildAvailable */ : "guildCreate" /* GuildCreate */, payload);
|
|
2839
3376
|
});
|
|
2840
3377
|
this.#gateway.on("GUILD_UPDATE", (data) => {
|
|
2841
3378
|
const guild = new Guild(data);
|
|
@@ -2964,10 +3501,52 @@ class Client extends EventEmitter {
|
|
|
2964
3501
|
return Promise.reject(new Error("Client is unauthenticated."));
|
|
2965
3502
|
return this.rest.post(`/webhooks/${this.user.id}/${token}`, data);
|
|
2966
3503
|
}
|
|
3504
|
+
fetchWebhook(id, token) {
|
|
3505
|
+
return this.rest.get(token ? `/webhooks/${id}/${token}` : `/webhooks/${id}`);
|
|
3506
|
+
}
|
|
3507
|
+
fetchGuildPreview(guildId) {
|
|
3508
|
+
return this.rest.get(`/guilds/${guildId}/preview`);
|
|
3509
|
+
}
|
|
3510
|
+
fetchVoiceRegions() {
|
|
3511
|
+
return this.rest.get("/voice/regions");
|
|
3512
|
+
}
|
|
3513
|
+
fetchInvite(code, options) {
|
|
3514
|
+
const query = new URLSearchParams;
|
|
3515
|
+
if (options?.withCounts)
|
|
3516
|
+
query.set("with_counts", "true");
|
|
3517
|
+
if (options?.withExpiration)
|
|
3518
|
+
query.set("with_expiration", "true");
|
|
3519
|
+
if (options?.guildScheduledEventId)
|
|
3520
|
+
query.set("guild_scheduled_event_id", options.guildScheduledEventId);
|
|
3521
|
+
const qs = query.toString();
|
|
3522
|
+
return this.rest.get(`/invites/${code}${qs ? `?${qs}` : ""}`);
|
|
3523
|
+
}
|
|
3524
|
+
fetchSticker(id) {
|
|
3525
|
+
return this.rest.get(`/stickers/${id}`);
|
|
3526
|
+
}
|
|
3527
|
+
fetchPremiumStickerPacks() {
|
|
3528
|
+
return this.rest.get(`/sticker-packs`);
|
|
3529
|
+
}
|
|
3530
|
+
fetchGuildTemplate(code) {
|
|
3531
|
+
return this.rest.get(`/guilds/templates/${code}`);
|
|
3532
|
+
}
|
|
3533
|
+
generateInvite(options) {
|
|
3534
|
+
if (!this.user)
|
|
3535
|
+
throw new Error("Client must be ready to generate invite.");
|
|
3536
|
+
const params = new URLSearchParams({
|
|
3537
|
+
client_id: this.user.id,
|
|
3538
|
+
scopes: (options?.scopes ?? ["bot"]).join(" ")
|
|
3539
|
+
});
|
|
3540
|
+
if (options?.permissions) {
|
|
3541
|
+
params.set("permissions", String(options.permissions));
|
|
3542
|
+
}
|
|
3543
|
+
return `https://discord.com/api/oauth2/authorize?${params.toString()}`;
|
|
3544
|
+
}
|
|
2967
3545
|
}
|
|
2968
3546
|
export {
|
|
2969
3547
|
Client,
|
|
2970
3548
|
ClientEvent,
|
|
3549
|
+
Collector,
|
|
2971
3550
|
GatewayIntentBits,
|
|
2972
3551
|
IntentBits,
|
|
2973
3552
|
Intents,
|
|
@@ -2980,4 +3559,4 @@ export {
|
|
|
2980
3559
|
resolveGatewayIntents
|
|
2981
3560
|
};
|
|
2982
3561
|
|
|
2983
|
-
//# debugId=
|
|
3562
|
+
//# debugId=5F8825194034E27864756E2164756E21
|