lunibee 0.2.3 → 0.3.0
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/attachment.d.ts +8 -4
- package/dist/builders/commands.d.ts +122 -149
- package/dist/builders/components.d.ts +10 -150
- package/dist/builders/embed.d.ts +66 -37
- package/dist/builders/index.d.ts +0 -4
- package/dist/builders/index.js +112 -221
- package/dist/builders/index.js.map +10 -9
- package/dist/collection/cache.d.ts +15 -6
- package/dist/collection/index.d.ts +92 -17
- package/dist/collection/index.js +471 -279
- package/dist/collection/index.js.map +4 -4
- package/dist/core/api.d.ts +130 -0
- package/dist/core/channel-create.d.ts +72 -0
- package/dist/core/commands.d.ts +232 -0
- package/dist/core/events.d.ts +24 -7
- package/dist/core/handles.d.ts +157 -0
- package/dist/core/index.d.ts +68 -4
- package/dist/core/index.js +2639 -493
- package/dist/core/index.js.map +47 -37
- package/dist/core/permissions.d.ts +7 -7
- package/dist/formatters/index.js +9 -5
- package/dist/formatters/index.js.map +3 -3
- package/dist/handlers/index.js +5 -10
- package/dist/handlers/index.js.map +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9527 -7809
- package/dist/index.js.map +63 -53
- package/dist/managers/advanced.d.ts +29 -1
- package/dist/managers/base.d.ts +22 -14
- package/dist/managers/emoji.d.ts +0 -2
- package/dist/managers/guild-resources.d.ts +13 -5
- package/dist/managers/guild.d.ts +40 -4
- package/dist/managers/index.d.ts +21 -13
- package/dist/managers/index.js +969 -386
- package/dist/managers/index.js.map +30 -25
- package/dist/managers/member.d.ts +9 -2
- package/dist/managers/message.d.ts +10 -15
- package/dist/managers/role.d.ts +18 -10
- package/dist/managers/thread.d.ts +68 -0
- package/dist/managers/user.d.ts +18 -0
- package/dist/rest/errors.d.ts +14 -7
- package/dist/rest/index.d.ts +24 -12
- package/dist/rest/index.js +70 -20
- package/dist/rest/index.js.map +9 -9
- package/dist/rest/redis.d.ts +1 -1
- package/dist/rest/route.d.ts +8 -4
- package/dist/rest/routes.d.ts +122 -48
- package/dist/rest/transport.d.ts +10 -5
- package/dist/rest/webhook.d.ts +9 -5
- package/dist/sharding/bus.d.ts +47 -19
- package/dist/sharding/cluster.d.ts +11 -0
- package/dist/sharding/gateway-bot.d.ts +18 -0
- package/dist/sharding/index.d.ts +64 -25
- package/dist/sharding/index.js +439 -124
- package/dist/sharding/index.js.map +19 -14
- package/dist/sharding/supervisor.d.ts +32 -0
- package/dist/sharding/transport.d.ts +45 -0
- package/dist/structures/audit-log.d.ts +99 -2
- package/dist/structures/base.d.ts +40 -23
- package/dist/structures/channels.d.ts +45 -14
- package/dist/structures/index.d.ts +8 -12
- package/dist/structures/index.js +280 -132
- package/dist/structures/index.js.map +21 -15
- package/dist/structures/interactions.d.ts +91 -63
- package/dist/structures/resources.d.ts +99 -52
- package/dist/structures/sticker.d.ts +33 -0
- package/dist/types/channel-kind.d.ts +26 -0
- package/dist/types/gateway.d.ts +24 -12
- package/dist/types/index.d.ts +115 -113
- package/dist/types/index.js +53 -48
- package/dist/types/index.js.map +6 -5
- package/dist/voice/index.d.ts +12 -4
- package/dist/voice/index.js +14 -18
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/decoder.d.ts +6 -2
- package/dist/ws/dispatcher.d.ts +19 -0
- package/dist/ws/index.d.ts +61 -15
- package/dist/ws/index.js +194 -77
- package/dist/ws/index.js.map +13 -11
- package/dist/ws/protocol.d.ts +10 -2
- package/dist/ws/reconnect.d.ts +10 -0
- package/dist/ws/send-budget.d.ts +6 -2
- package/dist/ws/session.d.ts +14 -4
- package/dist/ws/state.d.ts +22 -11
- package/package.json +20 -16
package/dist/core/index.js
CHANGED
|
@@ -5,7 +5,6 @@ var PermissionOverwriteEnum;
|
|
|
5
5
|
PermissionOverwriteEnum[PermissionOverwriteEnum["Role"] = 0] = "Role";
|
|
6
6
|
PermissionOverwriteEnum[PermissionOverwriteEnum["Member"] = 1] = "Member";
|
|
7
7
|
})(PermissionOverwriteEnum ||= {});
|
|
8
|
-
var PermissionOverwriteType = PermissionOverwriteEnum;
|
|
9
8
|
var Permission = {
|
|
10
9
|
createInstantInvite: 1n << 0n,
|
|
11
10
|
kickMembers: 1n << 1n,
|
|
@@ -114,60 +113,7 @@ var Permissions = {
|
|
|
114
113
|
PinMessages: 1n << 51n,
|
|
115
114
|
BypassSlowmode: 1n << 52n
|
|
116
115
|
};
|
|
117
|
-
var PermissionFlagsBits =
|
|
118
|
-
CreateInstantInvite: 1n << 0n,
|
|
119
|
-
KickMembers: 1n << 1n,
|
|
120
|
-
BanMembers: 1n << 2n,
|
|
121
|
-
Administrator: 1n << 3n,
|
|
122
|
-
ManageChannels: 1n << 4n,
|
|
123
|
-
ManageGuild: 1n << 5n,
|
|
124
|
-
AddReactions: 1n << 6n,
|
|
125
|
-
ViewAuditLog: 1n << 7n,
|
|
126
|
-
PrioritySpeaker: 1n << 8n,
|
|
127
|
-
Stream: 1n << 9n,
|
|
128
|
-
ViewChannel: 1n << 10n,
|
|
129
|
-
SendMessages: 1n << 11n,
|
|
130
|
-
SendTTSMessages: 1n << 12n,
|
|
131
|
-
ManageMessages: 1n << 13n,
|
|
132
|
-
EmbedLinks: 1n << 14n,
|
|
133
|
-
AttachFiles: 1n << 15n,
|
|
134
|
-
ReadMessageHistory: 1n << 16n,
|
|
135
|
-
MentionEveryone: 1n << 17n,
|
|
136
|
-
UseExternalEmojis: 1n << 18n,
|
|
137
|
-
ViewGuildInsights: 1n << 19n,
|
|
138
|
-
Connect: 1n << 20n,
|
|
139
|
-
Speak: 1n << 21n,
|
|
140
|
-
MuteMembers: 1n << 22n,
|
|
141
|
-
DeafenMembers: 1n << 23n,
|
|
142
|
-
MoveMembers: 1n << 24n,
|
|
143
|
-
UseVAD: 1n << 25n,
|
|
144
|
-
ChangeNickname: 1n << 26n,
|
|
145
|
-
ManageNicknames: 1n << 27n,
|
|
146
|
-
ManageRoles: 1n << 28n,
|
|
147
|
-
ManageWebhooks: 1n << 29n,
|
|
148
|
-
ManageGuildExpressions: 1n << 30n,
|
|
149
|
-
UseApplicationCommands: 1n << 31n,
|
|
150
|
-
RequestToSpeak: 1n << 32n,
|
|
151
|
-
ManageEvents: 1n << 33n,
|
|
152
|
-
ManageThreads: 1n << 34n,
|
|
153
|
-
CreatePublicThreads: 1n << 35n,
|
|
154
|
-
CreatePrivateThreads: 1n << 36n,
|
|
155
|
-
UseExternalStickers: 1n << 37n,
|
|
156
|
-
SendMessagesInThreads: 1n << 38n,
|
|
157
|
-
UseEmbeddedActivities: 1n << 39n,
|
|
158
|
-
ModerateMembers: 1n << 40n,
|
|
159
|
-
ViewCreatorMonetizationAnalytics: 1n << 41n,
|
|
160
|
-
UseSoundboard: 1n << 42n,
|
|
161
|
-
CreateGuildExpressions: 1n << 43n,
|
|
162
|
-
CreateEvents: 1n << 44n,
|
|
163
|
-
UseExternalSounds: 1n << 45n,
|
|
164
|
-
SendVoiceMessages: 1n << 46n,
|
|
165
|
-
SetVoiceChannelStatus: 1n << 48n,
|
|
166
|
-
SendPolls: 1n << 49n,
|
|
167
|
-
UseExternalApps: 1n << 50n,
|
|
168
|
-
PinMessages: 1n << 51n,
|
|
169
|
-
BypassSlowmode: 1n << 52n
|
|
170
|
-
};
|
|
116
|
+
var PermissionFlagsBits = Permissions;
|
|
171
117
|
|
|
172
118
|
class PermissionSet {
|
|
173
119
|
bitfield;
|
|
@@ -468,6 +414,9 @@ function computePermissions(context) {
|
|
|
468
414
|
const member = overwrites.find((o) => o.type === 1 /* Member */ && o.id === context.memberId);
|
|
469
415
|
if (member)
|
|
470
416
|
base = base & ~bits(member.deny) | bits(member.allow);
|
|
417
|
+
const until = context.timedOutUntil instanceof Date ? context.timedOutUntil.getTime() : context.timedOutUntil ?? 0;
|
|
418
|
+
if (until > Date.now())
|
|
419
|
+
base &= Permission.viewChannel | Permission.readMessageHistory;
|
|
471
420
|
return new PermissionSet(base);
|
|
472
421
|
}
|
|
473
422
|
// packages/core/src/events.ts
|
|
@@ -688,6 +637,152 @@ class Collector extends EventEmitter {
|
|
|
688
637
|
});
|
|
689
638
|
}
|
|
690
639
|
}
|
|
640
|
+
// packages/core/src/api.ts
|
|
641
|
+
var SAFE_WORD = /^[a-z][a-zA-Z0-9]*$/;
|
|
642
|
+
var SAFE_SEGMENT = /^[A-Za-z0-9_@.%-]+$/;
|
|
643
|
+
var PAGING = {
|
|
644
|
+
members: {
|
|
645
|
+
limit: 1000,
|
|
646
|
+
cursor: "after",
|
|
647
|
+
idOf: (member) => member.user.id
|
|
648
|
+
},
|
|
649
|
+
bans: {
|
|
650
|
+
limit: 1000,
|
|
651
|
+
cursor: "after",
|
|
652
|
+
idOf: (ban) => ban.user.id
|
|
653
|
+
},
|
|
654
|
+
messages: { limit: 100, cursor: "before" },
|
|
655
|
+
guilds: { limit: 200, cursor: "after" }
|
|
656
|
+
};
|
|
657
|
+
var DEFAULT_PAGING = { limit: 100, cursor: "after" };
|
|
658
|
+
var DEFAULT_MAX = 1e4;
|
|
659
|
+
function kebab(word) {
|
|
660
|
+
return word.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
661
|
+
}
|
|
662
|
+
function idSegment(id) {
|
|
663
|
+
if (typeof id !== "string" && typeof id !== "number" && typeof id !== "bigint")
|
|
664
|
+
throw new TypeError("A route id must be a string, number or bigint.");
|
|
665
|
+
const text = String(id);
|
|
666
|
+
if (text === "")
|
|
667
|
+
throw new TypeError("A route id cannot be empty.");
|
|
668
|
+
return encodeURIComponent(text).replace(/%40/g, "@");
|
|
669
|
+
}
|
|
670
|
+
function defaultId(item) {
|
|
671
|
+
const record = item;
|
|
672
|
+
const id = record?.id ?? record?.user?.id;
|
|
673
|
+
if (typeof id !== "string")
|
|
674
|
+
throw new TypeError("Cannot find an id on a page item; pass idOf to pages().");
|
|
675
|
+
return id;
|
|
676
|
+
}
|
|
677
|
+
function node(rest, segments) {
|
|
678
|
+
const path = `/${segments.join("/")}`;
|
|
679
|
+
const send = (method, hasBody) => (first, second) => rest.request(method, path, hasBody ? first : undefined, (hasBody ? second : first) ?? {});
|
|
680
|
+
const last = segments[segments.length - 1] ?? "";
|
|
681
|
+
const pages = async function* (options = {}) {
|
|
682
|
+
const paging = { ...DEFAULT_PAGING, ...PAGING[last] };
|
|
683
|
+
const cursorName = options.cursor ?? paging.cursor;
|
|
684
|
+
const limit = options.limit ?? paging.limit;
|
|
685
|
+
const idOf = options.idOf ?? paging.idOf ?? defaultId;
|
|
686
|
+
let cursor = options.start;
|
|
687
|
+
for (;; ) {
|
|
688
|
+
const batch = await rest.request("GET", path, undefined, {
|
|
689
|
+
signal: options.signal,
|
|
690
|
+
query: {
|
|
691
|
+
...options.query,
|
|
692
|
+
limit,
|
|
693
|
+
...cursor === undefined ? {} : { [cursorName]: cursor }
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
if (!Array.isArray(batch) || batch.length === 0)
|
|
697
|
+
return;
|
|
698
|
+
yield batch;
|
|
699
|
+
if (batch.length < limit)
|
|
700
|
+
return;
|
|
701
|
+
cursor = idOf(batch[batch.length - 1]);
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
const all = async (options = {}) => {
|
|
705
|
+
const max = options.max ?? DEFAULT_MAX;
|
|
706
|
+
const paging = { ...DEFAULT_PAGING, ...PAGING[last] };
|
|
707
|
+
const items = [];
|
|
708
|
+
if (max <= 0)
|
|
709
|
+
return items;
|
|
710
|
+
for await (const page of pages({
|
|
711
|
+
...options,
|
|
712
|
+
limit: Math.min(options.limit ?? paging.limit, max)
|
|
713
|
+
})) {
|
|
714
|
+
items.push(...page);
|
|
715
|
+
if (items.length >= max)
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
return items.slice(0, max);
|
|
719
|
+
};
|
|
720
|
+
const members = {
|
|
721
|
+
path,
|
|
722
|
+
get: send("GET", false),
|
|
723
|
+
post: send("POST", true),
|
|
724
|
+
put: send("PUT", true),
|
|
725
|
+
patch: send("PATCH", true),
|
|
726
|
+
delete: send("DELETE", false),
|
|
727
|
+
pages,
|
|
728
|
+
all,
|
|
729
|
+
toString: () => path
|
|
730
|
+
};
|
|
731
|
+
return new Proxy(function route() {}, {
|
|
732
|
+
get(_target, property) {
|
|
733
|
+
if (typeof property !== "string")
|
|
734
|
+
return;
|
|
735
|
+
if (property in members)
|
|
736
|
+
return members[property];
|
|
737
|
+
if (property === "then" || !SAFE_WORD.test(property))
|
|
738
|
+
return;
|
|
739
|
+
return node(rest, [...segments, kebab(property)]);
|
|
740
|
+
},
|
|
741
|
+
apply(_target, _this, args) {
|
|
742
|
+
if (args.length !== 1)
|
|
743
|
+
throw new TypeError(`Call a route with exactly one id, e.g. ${path}(id).`);
|
|
744
|
+
return node(rest, [...segments, idSegment(args[0])]);
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
function createApi(rest) {
|
|
749
|
+
const root = node(rest, []);
|
|
750
|
+
return new Proxy(root, {
|
|
751
|
+
get(target, property, receiver) {
|
|
752
|
+
if (property === "to")
|
|
753
|
+
return (...segments) => {
|
|
754
|
+
if (segments.length === 0)
|
|
755
|
+
throw new TypeError("to() needs at least one segment.");
|
|
756
|
+
const cleaned = segments.map((segment) => {
|
|
757
|
+
const text = String(segment);
|
|
758
|
+
if (!SAFE_SEGMENT.test(text))
|
|
759
|
+
throw new TypeError(`Invalid route segment: ${JSON.stringify(text)}.`);
|
|
760
|
+
return text;
|
|
761
|
+
});
|
|
762
|
+
return node(rest, cleaned);
|
|
763
|
+
};
|
|
764
|
+
return Reflect.get(target, property, receiver);
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
// packages/types/src/channel-kind.ts
|
|
769
|
+
var ChannelKinds = {
|
|
770
|
+
text: [0],
|
|
771
|
+
dm: [1],
|
|
772
|
+
voice: [2],
|
|
773
|
+
"group-dm": [3],
|
|
774
|
+
category: [4],
|
|
775
|
+
announcement: [5],
|
|
776
|
+
thread: [10, 11, 12],
|
|
777
|
+
stage: [13],
|
|
778
|
+
directory: [14],
|
|
779
|
+
forum: [15],
|
|
780
|
+
media: [16]
|
|
781
|
+
};
|
|
782
|
+
var KIND_OF_TYPE = new Map(Object.keys(ChannelKinds).flatMap((kind) => ChannelKinds[kind].map((type) => [type, kind])));
|
|
783
|
+
function channelKindOf(type) {
|
|
784
|
+
return KIND_OF_TYPE.get(type) ?? "unknown";
|
|
785
|
+
}
|
|
691
786
|
// packages/types/src/gateway.ts
|
|
692
787
|
var GatewayIntentBits = {
|
|
693
788
|
Guilds: 1 << 0,
|
|
@@ -742,220 +837,1427 @@ var IntentBits = {
|
|
|
742
837
|
};
|
|
743
838
|
var Intents = IntentBits;
|
|
744
839
|
function resolveGatewayIntents(intents) {
|
|
745
|
-
if (
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
return 0;
|
|
840
|
+
if (!Array.isArray(intents))
|
|
841
|
+
throw new TypeError("Gateway intents must be an array, e.g. [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages].");
|
|
842
|
+
return intents.reduce((acc, intent) => acc | resolveIntent(intent), 0);
|
|
843
|
+
}
|
|
844
|
+
function resolveIntent(intent) {
|
|
845
|
+
if (typeof intent === "number")
|
|
846
|
+
return intent;
|
|
847
|
+
const bits = {
|
|
848
|
+
...IntentBits,
|
|
849
|
+
...GatewayIntentBits
|
|
850
|
+
};
|
|
851
|
+
const lower = intent.charAt(0).toLowerCase() + intent.slice(1);
|
|
852
|
+
if (Object.hasOwn(bits, intent))
|
|
853
|
+
return bits[intent];
|
|
854
|
+
if (Object.hasOwn(bits, lower))
|
|
855
|
+
return bits[lower];
|
|
856
|
+
const num = Number(intent);
|
|
857
|
+
return Number.isNaN(num) ? 0 : num;
|
|
858
|
+
}
|
|
859
|
+
function resolveInput(bits) {
|
|
860
|
+
return resolveGatewayIntents(Array.isArray(bits) ? bits : [bits]);
|
|
767
861
|
}
|
|
768
862
|
|
|
769
863
|
class IntentsBitField {
|
|
770
864
|
static Flags = GatewayIntentBits;
|
|
771
865
|
bitfield;
|
|
772
|
-
constructor(bits =
|
|
773
|
-
this.bitfield =
|
|
866
|
+
constructor(bits = []) {
|
|
867
|
+
this.bitfield = resolveInput(bits);
|
|
774
868
|
}
|
|
775
869
|
has(bits) {
|
|
776
|
-
const resolved =
|
|
870
|
+
const resolved = resolveInput(bits);
|
|
777
871
|
return (this.bitfield & resolved) === resolved;
|
|
778
872
|
}
|
|
779
873
|
any(bits) {
|
|
780
|
-
return (this.bitfield &
|
|
874
|
+
return (this.bitfield & resolveInput(bits)) !== 0;
|
|
781
875
|
}
|
|
782
876
|
add(...bits) {
|
|
783
877
|
for (const bit of bits)
|
|
784
|
-
this.bitfield |=
|
|
878
|
+
this.bitfield |= resolveInput(bit);
|
|
785
879
|
return this;
|
|
786
880
|
}
|
|
787
881
|
remove(...bits) {
|
|
788
882
|
for (const bit of bits)
|
|
789
|
-
this.bitfield &= ~
|
|
883
|
+
this.bitfield &= ~resolveInput(bit);
|
|
884
|
+
return this;
|
|
885
|
+
}
|
|
886
|
+
toArray() {
|
|
887
|
+
return Object.keys(GatewayIntentBits).filter((name) => this.has(GatewayIntentBits[name]));
|
|
888
|
+
}
|
|
889
|
+
equals(bits) {
|
|
890
|
+
return this.bitfield === resolveInput(bits);
|
|
891
|
+
}
|
|
892
|
+
valueOf() {
|
|
893
|
+
return this.bitfield;
|
|
894
|
+
}
|
|
895
|
+
toJSON() {
|
|
896
|
+
return this.bitfield;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
// packages/types/src/index.ts
|
|
900
|
+
var InteractionResponseEnum = {
|
|
901
|
+
Pong: 1,
|
|
902
|
+
ChannelMessage: 4,
|
|
903
|
+
DeferredChannelMessage: 5,
|
|
904
|
+
DeferredMessageUpdate: 6,
|
|
905
|
+
MessageUpdate: 7,
|
|
906
|
+
Autocomplete: 8,
|
|
907
|
+
Modal: 9
|
|
908
|
+
};
|
|
909
|
+
var ActivityEnum = {
|
|
910
|
+
Playing: 0,
|
|
911
|
+
Streaming: 1,
|
|
912
|
+
Listening: 2,
|
|
913
|
+
Watching: 3,
|
|
914
|
+
Custom: 4,
|
|
915
|
+
Competing: 5
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
// packages/builders/src/components.ts
|
|
919
|
+
var IS_COMPONENTS_V2 = 1 << 15;
|
|
920
|
+
// packages/builders/src/commands.ts
|
|
921
|
+
var ApplicationCommandOptionEnum = {
|
|
922
|
+
Subcommand: 1,
|
|
923
|
+
SubcommandGroup: 2,
|
|
924
|
+
String: 3,
|
|
925
|
+
Integer: 4,
|
|
926
|
+
Boolean: 5,
|
|
927
|
+
User: 6,
|
|
928
|
+
Channel: 7,
|
|
929
|
+
Role: 8,
|
|
930
|
+
Mentionable: 9,
|
|
931
|
+
Number: 10,
|
|
932
|
+
Attachment: 11
|
|
933
|
+
};
|
|
934
|
+
function validateContexts(contexts) {
|
|
935
|
+
if (contexts.some((context) => context !== 0 && context !== 1 && context !== 2))
|
|
936
|
+
throw new RangeError("Command contexts must be 0, 1 or 2.");
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
class CreateSlashCommand {
|
|
940
|
+
#data = { type: 1 };
|
|
941
|
+
setName(name) {
|
|
942
|
+
validateName(name, "Command name");
|
|
943
|
+
this.#data.name = name;
|
|
944
|
+
return this;
|
|
945
|
+
}
|
|
946
|
+
setDescription(description) {
|
|
947
|
+
validateText(description, "Command description", 100);
|
|
948
|
+
this.#data.description = description;
|
|
949
|
+
return this;
|
|
950
|
+
}
|
|
951
|
+
setContexts(...contexts) {
|
|
952
|
+
validateContexts(contexts);
|
|
953
|
+
this.#data.contexts = [...contexts];
|
|
954
|
+
return this;
|
|
955
|
+
}
|
|
956
|
+
setNSFW(nsfw = true) {
|
|
957
|
+
this.#data.nsfw = nsfw;
|
|
958
|
+
return this;
|
|
959
|
+
}
|
|
960
|
+
setNsfw(nsfw = true) {
|
|
961
|
+
return this.setNSFW(nsfw);
|
|
962
|
+
}
|
|
963
|
+
setDefaultMemberPermissions(permissions) {
|
|
964
|
+
this.#data.default_member_permissions = permissions === null ? null : BigInt(permissions).toString();
|
|
965
|
+
return this;
|
|
966
|
+
}
|
|
967
|
+
setIntegrationTypes(...types) {
|
|
968
|
+
this.#data.integration_types = [...types];
|
|
969
|
+
return this;
|
|
970
|
+
}
|
|
971
|
+
addStringOption(configure) {
|
|
972
|
+
return this.addOption(configure(new CreateStringOption));
|
|
973
|
+
}
|
|
974
|
+
addIntegerOption(configure) {
|
|
975
|
+
return this.addOption(configure(new CreateIntegerOption));
|
|
976
|
+
}
|
|
977
|
+
addNumberOption(configure) {
|
|
978
|
+
return this.addOption(configure(new CreateNumberOption));
|
|
979
|
+
}
|
|
980
|
+
addBooleanOption(configure) {
|
|
981
|
+
return this.addOption(configure(new CreateBooleanOption));
|
|
982
|
+
}
|
|
983
|
+
addUserOption(configure) {
|
|
984
|
+
return this.addOption(configure(new CreateUserOption));
|
|
985
|
+
}
|
|
986
|
+
addChannelOption(configure) {
|
|
987
|
+
return this.addOption(configure(new CreateChannelOption));
|
|
988
|
+
}
|
|
989
|
+
addRoleOption(configure) {
|
|
990
|
+
return this.addOption(configure(new CreateRoleOption));
|
|
991
|
+
}
|
|
992
|
+
addMentionableOption(configure) {
|
|
993
|
+
return this.addOption(configure(new CreateMentionableOption));
|
|
994
|
+
}
|
|
995
|
+
addAttachmentOption(configure) {
|
|
996
|
+
return this.addOption(configure(new CreateAttachmentOption));
|
|
997
|
+
}
|
|
998
|
+
addSubcommand(configure) {
|
|
999
|
+
return this.addOption(configure(new CreateSubcommand));
|
|
1000
|
+
}
|
|
1001
|
+
addSubcommandGroup(configure) {
|
|
1002
|
+
return this.addOption(configure(new CreateSubcommandGroup));
|
|
1003
|
+
}
|
|
1004
|
+
toJSON() {
|
|
1005
|
+
return structuredClone(this.#data);
|
|
1006
|
+
}
|
|
1007
|
+
addOption(option) {
|
|
1008
|
+
this.#data.options = appendOption(this.#data.options, option.toJSON(), "application command");
|
|
1009
|
+
return this;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
class CreateCommandOption {
|
|
1014
|
+
data;
|
|
1015
|
+
constructor(type) {
|
|
1016
|
+
this.data = { type };
|
|
1017
|
+
}
|
|
1018
|
+
setName(name) {
|
|
1019
|
+
validateName(name, "Option name");
|
|
1020
|
+
this.data.name = name;
|
|
1021
|
+
return this;
|
|
1022
|
+
}
|
|
1023
|
+
setDescription(description) {
|
|
1024
|
+
validateText(description, "Option description", 100);
|
|
1025
|
+
this.data.description = description;
|
|
1026
|
+
return this;
|
|
1027
|
+
}
|
|
1028
|
+
setRequired(required = true) {
|
|
1029
|
+
this.data.required = required;
|
|
1030
|
+
return this;
|
|
1031
|
+
}
|
|
1032
|
+
setAutocomplete(enabled = true) {
|
|
1033
|
+
this.data.autocomplete = enabled;
|
|
1034
|
+
return this;
|
|
1035
|
+
}
|
|
1036
|
+
toJSON() {
|
|
1037
|
+
return structuredClone(this.data);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
class CreateStringOption extends CreateCommandOption {
|
|
1042
|
+
constructor() {
|
|
1043
|
+
super(ApplicationCommandOptionEnum.String);
|
|
1044
|
+
}
|
|
1045
|
+
addChoices(...choices) {
|
|
1046
|
+
for (const choice of choices)
|
|
1047
|
+
validateText(choice.value, "Choice value", 100);
|
|
1048
|
+
appendChoices(this.data, choices);
|
|
1049
|
+
return this;
|
|
1050
|
+
}
|
|
1051
|
+
setMinLength(value) {
|
|
1052
|
+
validateIntegerRange(value, 0, 6000, "min_length");
|
|
1053
|
+
this.data.min_length = value;
|
|
1054
|
+
return this;
|
|
1055
|
+
}
|
|
1056
|
+
setMaxLength(value) {
|
|
1057
|
+
validateIntegerRange(value, 1, 6000, "max_length");
|
|
1058
|
+
if (this.data.min_length !== undefined && this.data.min_length > value)
|
|
1059
|
+
throw new RangeError("min_length cannot exceed max_length.");
|
|
1060
|
+
this.data.max_length = value;
|
|
1061
|
+
return this;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
class CreateNumericOption extends CreateCommandOption {
|
|
1066
|
+
#integer;
|
|
1067
|
+
constructor(type, integer) {
|
|
1068
|
+
super(type);
|
|
1069
|
+
this.#integer = integer;
|
|
1070
|
+
}
|
|
1071
|
+
setMinValue(value) {
|
|
1072
|
+
validateNumberRange(value, -MAX_SAFE, MAX_SAFE, "min_value", this.#integer);
|
|
1073
|
+
this.data.min_value = value;
|
|
1074
|
+
return this;
|
|
1075
|
+
}
|
|
1076
|
+
setMaxValue(value) {
|
|
1077
|
+
validateNumberRange(value, -MAX_SAFE, MAX_SAFE, "max_value", this.#integer);
|
|
1078
|
+
const min = this.data.min_value;
|
|
1079
|
+
if (min !== undefined && min > value)
|
|
1080
|
+
throw new RangeError("min_value cannot exceed max_value.");
|
|
1081
|
+
this.data.max_value = value;
|
|
1082
|
+
return this;
|
|
1083
|
+
}
|
|
1084
|
+
setAutocomplete(enabled = true) {
|
|
1085
|
+
if (enabled && Array.isArray(this.data.choices) && this.data.choices.length)
|
|
1086
|
+
throw new RangeError("Autocomplete options cannot define choices.");
|
|
1087
|
+
this.data.autocomplete = enabled;
|
|
1088
|
+
return this;
|
|
1089
|
+
}
|
|
1090
|
+
addChoices(...choices) {
|
|
1091
|
+
appendChoices(this.data, choices);
|
|
1092
|
+
return this;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
class CreateIntegerOption extends CreateNumericOption {
|
|
1097
|
+
constructor() {
|
|
1098
|
+
super(ApplicationCommandOptionEnum.Integer, true);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
class CreateNumberOption extends CreateNumericOption {
|
|
1103
|
+
constructor() {
|
|
1104
|
+
super(ApplicationCommandOptionEnum.Number, false);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
class CreateBooleanOption extends CreateCommandOption {
|
|
1109
|
+
constructor() {
|
|
1110
|
+
super(ApplicationCommandOptionEnum.Boolean);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
class CreateUserOption extends CreateCommandOption {
|
|
1115
|
+
constructor() {
|
|
1116
|
+
super(ApplicationCommandOptionEnum.User);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
class CreateRoleOption extends CreateCommandOption {
|
|
1121
|
+
constructor() {
|
|
1122
|
+
super(ApplicationCommandOptionEnum.Role);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
class CreateMentionableOption extends CreateCommandOption {
|
|
1127
|
+
constructor() {
|
|
1128
|
+
super(ApplicationCommandOptionEnum.Mentionable);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
class CreateAttachmentOption extends CreateCommandOption {
|
|
1133
|
+
constructor() {
|
|
1134
|
+
super(ApplicationCommandOptionEnum.Attachment);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
class CreateChannelOption extends CreateCommandOption {
|
|
1139
|
+
constructor() {
|
|
1140
|
+
super(ApplicationCommandOptionEnum.Channel);
|
|
1141
|
+
}
|
|
1142
|
+
addChannelTypes(...types) {
|
|
1143
|
+
if (types.some((type) => !Number.isInteger(type) || type < 0))
|
|
1144
|
+
throw new RangeError("Channel types must be non-negative integers.");
|
|
1145
|
+
this.data.channel_types = [...new Set(types)];
|
|
1146
|
+
return this;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
class CreateSubcommand extends CreateCommandOption {
|
|
1151
|
+
constructor() {
|
|
1152
|
+
super(ApplicationCommandOptionEnum.Subcommand);
|
|
1153
|
+
}
|
|
1154
|
+
addStringOption(configure) {
|
|
1155
|
+
return this.addChildOption(configure(new CreateStringOption));
|
|
1156
|
+
}
|
|
1157
|
+
addIntegerOption(configure) {
|
|
1158
|
+
return this.addChildOption(configure(new CreateIntegerOption));
|
|
1159
|
+
}
|
|
1160
|
+
addNumberOption(configure) {
|
|
1161
|
+
return this.addChildOption(configure(new CreateNumberOption));
|
|
1162
|
+
}
|
|
1163
|
+
addBooleanOption(configure) {
|
|
1164
|
+
return this.addChildOption(configure(new CreateBooleanOption));
|
|
1165
|
+
}
|
|
1166
|
+
addUserOption(configure) {
|
|
1167
|
+
return this.addChildOption(configure(new CreateUserOption));
|
|
1168
|
+
}
|
|
1169
|
+
addChannelOption(configure) {
|
|
1170
|
+
return this.addChildOption(configure(new CreateChannelOption));
|
|
1171
|
+
}
|
|
1172
|
+
addRoleOption(configure) {
|
|
1173
|
+
return this.addChildOption(configure(new CreateRoleOption));
|
|
1174
|
+
}
|
|
1175
|
+
addMentionableOption(configure) {
|
|
1176
|
+
return this.addChildOption(configure(new CreateMentionableOption));
|
|
1177
|
+
}
|
|
1178
|
+
addAttachmentOption(configure) {
|
|
1179
|
+
return this.addChildOption(configure(new CreateAttachmentOption));
|
|
1180
|
+
}
|
|
1181
|
+
addChildOption(option) {
|
|
1182
|
+
const options = this.data.options ?? [];
|
|
1183
|
+
if (options.some((existing) => existing.type === ApplicationCommandOptionEnum.Subcommand))
|
|
1184
|
+
throw new RangeError("Subcommands cannot contain nested subcommands.");
|
|
1185
|
+
this.data.options = appendOption(options, option.toJSON(), "subcommand");
|
|
1186
|
+
return this;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
class CreateSubcommandGroup extends CreateCommandOption {
|
|
1191
|
+
constructor() {
|
|
1192
|
+
super(ApplicationCommandOptionEnum.SubcommandGroup);
|
|
1193
|
+
}
|
|
1194
|
+
addSubcommand(configure) {
|
|
1195
|
+
const options = this.data.options ?? [];
|
|
1196
|
+
if (options.length >= 25)
|
|
1197
|
+
throw new RangeError("A subcommand group cannot contain more than 25 subcommands.");
|
|
1198
|
+
const payload = configure(new CreateSubcommand).toJSON();
|
|
1199
|
+
if (options.some((existing) => existing.name === payload.name))
|
|
1200
|
+
throw new RangeError(`Duplicate subcommand name: ${String(payload.name)}.`);
|
|
1201
|
+
if (payload.type !== ApplicationCommandOptionEnum.Subcommand)
|
|
1202
|
+
throw new TypeError("Subcommand group children must be subcommands.");
|
|
1203
|
+
options.push(payload);
|
|
1204
|
+
this.data.options = options;
|
|
790
1205
|
return this;
|
|
791
1206
|
}
|
|
792
|
-
|
|
793
|
-
|
|
1207
|
+
}
|
|
1208
|
+
var MAX_SAFE = Number.MAX_SAFE_INTEGER;
|
|
1209
|
+
function appendOption(options, payload, parent) {
|
|
1210
|
+
const list = options ?? [];
|
|
1211
|
+
if (list.length >= 25)
|
|
1212
|
+
throw new RangeError(`${parent === "subcommand" ? "A subcommand" : "An application command"} cannot contain more than 25 options.`);
|
|
1213
|
+
if (list.some((existing) => existing.name === payload.name))
|
|
1214
|
+
throw new RangeError(`Duplicate option name: ${String(payload.name)}.`);
|
|
1215
|
+
if (payload.required === true && list.some((existing) => existing.required !== true))
|
|
1216
|
+
throw new RangeError(`Required ${parent} options must be placed before optional options.`);
|
|
1217
|
+
return [...list, payload];
|
|
1218
|
+
}
|
|
1219
|
+
function appendChoices(data, choices) {
|
|
1220
|
+
const current = data.choices ?? [];
|
|
1221
|
+
if (!choices.length)
|
|
1222
|
+
throw new TypeError("At least one choice is required.");
|
|
1223
|
+
if (data.autocomplete === true)
|
|
1224
|
+
throw new RangeError("Autocomplete options cannot define choices.");
|
|
1225
|
+
if (current.length + choices.length > 25)
|
|
1226
|
+
throw new RangeError("An option cannot contain more than 25 choices.");
|
|
1227
|
+
for (const choice of choices)
|
|
1228
|
+
validateText(choice.name, "Choice name", 100);
|
|
1229
|
+
data.choices = [...current, ...choices.map((choice) => ({ ...choice }))];
|
|
1230
|
+
}
|
|
1231
|
+
function validateName(value, field) {
|
|
1232
|
+
if (!/^[\p{L}\p{N}_-]{1,32}$/u.test(value) || value !== value.toLowerCase())
|
|
1233
|
+
throw new RangeError(`${field} must contain 1-32 lowercase letters, numbers, underscores, or hyphens.`);
|
|
1234
|
+
}
|
|
1235
|
+
function validateText(value, field, max) {
|
|
1236
|
+
if (typeof value !== "string" || !value.trim() || value.length > max)
|
|
1237
|
+
throw new RangeError(`${field} must contain 1-${max} characters.`);
|
|
1238
|
+
}
|
|
1239
|
+
function validateIntegerRange(value, minimum, maximum, field) {
|
|
1240
|
+
if (!Number.isInteger(value) || value < minimum || value > maximum)
|
|
1241
|
+
throw new RangeError(`${field} must be an integer between ${minimum} and ${maximum}.`);
|
|
1242
|
+
}
|
|
1243
|
+
function validateNumberRange(value, minimum, maximum, field, integerOnly = true) {
|
|
1244
|
+
if (!Number.isFinite(value) || integerOnly && !Number.isInteger(value) || value < minimum || value > maximum)
|
|
1245
|
+
throw new RangeError(`${field} must be ${integerOnly ? "an integer" : "a number"} between ${minimum} and ${maximum}.`);
|
|
1246
|
+
}
|
|
1247
|
+
// packages/utils/src/args.ts
|
|
1248
|
+
var SNOWFLAKE = /^\d{16,22}$/;
|
|
1249
|
+
var TRUE_WORDS = new Set([
|
|
1250
|
+
"true",
|
|
1251
|
+
"yes",
|
|
1252
|
+
"y",
|
|
1253
|
+
"on",
|
|
1254
|
+
"1",
|
|
1255
|
+
"enable",
|
|
1256
|
+
"enabled"
|
|
1257
|
+
]);
|
|
1258
|
+
var FALSE_WORDS = new Set([
|
|
1259
|
+
"false",
|
|
1260
|
+
"no",
|
|
1261
|
+
"n",
|
|
1262
|
+
"off",
|
|
1263
|
+
"0",
|
|
1264
|
+
"disable",
|
|
1265
|
+
"disabled"
|
|
1266
|
+
]);
|
|
1267
|
+
function tokenizeArgs(input) {
|
|
1268
|
+
const args = [];
|
|
1269
|
+
let current = "";
|
|
1270
|
+
let quote = null;
|
|
1271
|
+
let started = false;
|
|
1272
|
+
for (let index = 0;index < input.length; index++) {
|
|
1273
|
+
const character = input[index];
|
|
1274
|
+
if (character === "\\" && index + 1 < input.length) {
|
|
1275
|
+
current += input[++index];
|
|
1276
|
+
started = true;
|
|
1277
|
+
} else if (quote) {
|
|
1278
|
+
if (character === quote)
|
|
1279
|
+
quote = null;
|
|
1280
|
+
else
|
|
1281
|
+
current += character;
|
|
1282
|
+
} else if (character === '"' || character === "'") {
|
|
1283
|
+
if (started)
|
|
1284
|
+
current += character;
|
|
1285
|
+
else {
|
|
1286
|
+
quote = character;
|
|
1287
|
+
started = true;
|
|
1288
|
+
}
|
|
1289
|
+
} else if (/\s/.test(character)) {
|
|
1290
|
+
if (started)
|
|
1291
|
+
args.push(current);
|
|
1292
|
+
current = "";
|
|
1293
|
+
started = false;
|
|
1294
|
+
} else {
|
|
1295
|
+
current += character;
|
|
1296
|
+
started = true;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
if (started)
|
|
1300
|
+
args.push(current);
|
|
1301
|
+
return args;
|
|
1302
|
+
}
|
|
1303
|
+
function parseUserMention(value) {
|
|
1304
|
+
const id = /^<@!?(\d{16,22})>$/.exec(value)?.[1] ?? value;
|
|
1305
|
+
return SNOWFLAKE.test(id) ? id : null;
|
|
1306
|
+
}
|
|
1307
|
+
function parseRoleMention(value) {
|
|
1308
|
+
const id = /^<@&(\d{16,22})>$/.exec(value)?.[1] ?? value;
|
|
1309
|
+
return SNOWFLAKE.test(id) ? id : null;
|
|
1310
|
+
}
|
|
1311
|
+
function parseChannelMention(value) {
|
|
1312
|
+
const id = /^<#(\d{16,22})>$/.exec(value)?.[1] ?? value;
|
|
1313
|
+
return SNOWFLAKE.test(id) ? id : null;
|
|
1314
|
+
}
|
|
1315
|
+
function parseMentionable(value) {
|
|
1316
|
+
const role = /^<@&(\d{16,22})>$/.exec(value)?.[1];
|
|
1317
|
+
if (role)
|
|
1318
|
+
return { id: role, type: "role" };
|
|
1319
|
+
const user = parseUserMention(value);
|
|
1320
|
+
return user ? { id: user, type: "user" } : null;
|
|
1321
|
+
}
|
|
1322
|
+
function readOne(spec, raw) {
|
|
1323
|
+
switch (spec.type) {
|
|
1324
|
+
case "string":
|
|
1325
|
+
case "rest":
|
|
1326
|
+
if (spec.maxLength !== undefined && raw.length > spec.maxLength)
|
|
1327
|
+
return {
|
|
1328
|
+
error: `must be at most ${spec.maxLength} characters`
|
|
1329
|
+
};
|
|
1330
|
+
if (spec.choices && !spec.choices.some((choice) => String(choice).toLowerCase() === raw.toLowerCase()))
|
|
1331
|
+
return { error: `must be one of: ${spec.choices.join(", ")}` };
|
|
1332
|
+
return { value: raw };
|
|
1333
|
+
case "integer":
|
|
1334
|
+
case "number": {
|
|
1335
|
+
const value = Number(raw);
|
|
1336
|
+
if (!Number.isFinite(value) || raw.trim() === "")
|
|
1337
|
+
return { error: "must be a number" };
|
|
1338
|
+
if (spec.type === "integer" && !Number.isSafeInteger(value))
|
|
1339
|
+
return { error: "must be a whole number" };
|
|
1340
|
+
if (spec.min !== undefined && value < spec.min)
|
|
1341
|
+
return { error: `must be at least ${spec.min}` };
|
|
1342
|
+
if (spec.max !== undefined && value > spec.max)
|
|
1343
|
+
return { error: `must be at most ${spec.max}` };
|
|
1344
|
+
if (spec.choices && !spec.choices.includes(value))
|
|
1345
|
+
return { error: `must be one of: ${spec.choices.join(", ")}` };
|
|
1346
|
+
return { value };
|
|
1347
|
+
}
|
|
1348
|
+
case "boolean": {
|
|
1349
|
+
const word = raw.toLowerCase();
|
|
1350
|
+
if (TRUE_WORDS.has(word))
|
|
1351
|
+
return { value: true };
|
|
1352
|
+
if (FALSE_WORDS.has(word))
|
|
1353
|
+
return { value: false };
|
|
1354
|
+
return { error: "must be yes or no" };
|
|
1355
|
+
}
|
|
1356
|
+
case "user": {
|
|
1357
|
+
const id = parseUserMention(raw);
|
|
1358
|
+
return id ? { value: id } : { error: "must be a user mention or ID" };
|
|
1359
|
+
}
|
|
1360
|
+
case "role": {
|
|
1361
|
+
const id = parseRoleMention(raw);
|
|
1362
|
+
return id ? { value: id } : { error: "must be a role mention or ID" };
|
|
1363
|
+
}
|
|
1364
|
+
case "channel": {
|
|
1365
|
+
const id = parseChannelMention(raw);
|
|
1366
|
+
return id ? { value: id } : { error: "must be a channel mention or ID" };
|
|
1367
|
+
}
|
|
1368
|
+
case "mentionable": {
|
|
1369
|
+
const value = parseMentionable(raw);
|
|
1370
|
+
return value ? { value } : { error: "must be a user or role mention" };
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
function parsePrefixArgs(input, specs) {
|
|
1375
|
+
const args = typeof input === "string" ? tokenizeArgs(input) : [...input];
|
|
1376
|
+
const values = {};
|
|
1377
|
+
let position = 0;
|
|
1378
|
+
for (const [index, spec] of specs.entries()) {
|
|
1379
|
+
if (spec.type === "rest" && index !== specs.length - 1)
|
|
1380
|
+
throw new TypeError(`The rest argument "${spec.name}" must be the last one.`);
|
|
1381
|
+
const raw = spec.type === "rest" ? args.slice(position).join(" ") : args[position];
|
|
1382
|
+
if (raw === undefined || raw === "") {
|
|
1383
|
+
if (spec.required)
|
|
1384
|
+
return { ok: false, arg: spec.name, error: "is required" };
|
|
1385
|
+
values[spec.name] = undefined;
|
|
1386
|
+
continue;
|
|
1387
|
+
}
|
|
1388
|
+
const read = readOne(spec, raw);
|
|
1389
|
+
if ("error" in read)
|
|
1390
|
+
return { ok: false, arg: spec.name, error: read.error };
|
|
1391
|
+
values[spec.name] = read.value;
|
|
1392
|
+
position += spec.type === "rest" ? args.length : 1;
|
|
1393
|
+
}
|
|
1394
|
+
return { ok: true, values };
|
|
1395
|
+
}
|
|
1396
|
+
// packages/core/src/commands.ts
|
|
1397
|
+
function settings(def) {
|
|
1398
|
+
return def.config;
|
|
1399
|
+
}
|
|
1400
|
+
function define(kind, config, words) {
|
|
1401
|
+
return { kind, config: config ?? {}, words };
|
|
1402
|
+
}
|
|
1403
|
+
var option = {
|
|
1404
|
+
string: (config) => define("string", config),
|
|
1405
|
+
integer: (config) => define("integer", config),
|
|
1406
|
+
number: (config) => define("number", config),
|
|
1407
|
+
boolean: (config) => define("boolean", config),
|
|
1408
|
+
user: (config) => define("user", config),
|
|
1409
|
+
role: (config) => define("role", config),
|
|
1410
|
+
channel: (config) => define("channel", config),
|
|
1411
|
+
mentionable: (config) => define("mentionable", config),
|
|
1412
|
+
attachment: (config) => define("attachment", config),
|
|
1413
|
+
choice: (words, config) => define("string", config, words)
|
|
1414
|
+
};
|
|
1415
|
+
var COMMAND_NAME = /^[-_\p{Ll}\p{Lo}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$/u;
|
|
1416
|
+
var channelTypes = (kinds) => [
|
|
1417
|
+
...new Set(kinds.flatMap((kind) => ChannelKinds[kind]))
|
|
1418
|
+
];
|
|
1419
|
+
function named(builder, name, def) {
|
|
1420
|
+
const config = settings(def);
|
|
1421
|
+
return builder.setName(name).setDescription(config.description ?? name).setRequired(config.required === true);
|
|
1422
|
+
}
|
|
1423
|
+
function addOptionTo(slash, name, def) {
|
|
1424
|
+
switch (def.kind) {
|
|
1425
|
+
case "string": {
|
|
1426
|
+
const config = def.config;
|
|
1427
|
+
const text = named(new CreateStringOption, name, def);
|
|
1428
|
+
if (config.min !== undefined)
|
|
1429
|
+
text.setMinLength(config.min);
|
|
1430
|
+
if (config.max !== undefined)
|
|
1431
|
+
text.setMaxLength(config.max);
|
|
1432
|
+
const choices = def.words ?? config.choices;
|
|
1433
|
+
if (choices?.length)
|
|
1434
|
+
text.addChoices(...choices.map((choice) => typeof choice === "string" ? { name: choice, value: choice } : choice));
|
|
1435
|
+
slash.addStringOption(() => text);
|
|
1436
|
+
break;
|
|
1437
|
+
}
|
|
1438
|
+
case "integer":
|
|
1439
|
+
case "number": {
|
|
1440
|
+
const config = def.config;
|
|
1441
|
+
const numeric = named(def.kind === "integer" ? new CreateIntegerOption : new CreateNumberOption, name, def);
|
|
1442
|
+
if (config.min !== undefined)
|
|
1443
|
+
numeric.setMinValue(config.min);
|
|
1444
|
+
if (config.max !== undefined)
|
|
1445
|
+
numeric.setMaxValue(config.max);
|
|
1446
|
+
if (config.choices?.length)
|
|
1447
|
+
numeric.addChoices(...config.choices.map((choice) => typeof choice === "number" ? { name: String(choice), value: choice } : choice));
|
|
1448
|
+
if (def.kind === "integer")
|
|
1449
|
+
slash.addIntegerOption(() => numeric);
|
|
1450
|
+
else
|
|
1451
|
+
slash.addNumberOption(() => numeric);
|
|
1452
|
+
break;
|
|
1453
|
+
}
|
|
1454
|
+
case "boolean":
|
|
1455
|
+
slash.addBooleanOption(() => named(new CreateBooleanOption, name, def));
|
|
1456
|
+
break;
|
|
1457
|
+
case "user":
|
|
1458
|
+
slash.addUserOption(() => named(new CreateUserOption, name, def));
|
|
1459
|
+
break;
|
|
1460
|
+
case "role":
|
|
1461
|
+
slash.addRoleOption(() => named(new CreateRoleOption, name, def));
|
|
1462
|
+
break;
|
|
1463
|
+
case "mentionable":
|
|
1464
|
+
slash.addMentionableOption(() => named(new CreateMentionableOption, name, def));
|
|
1465
|
+
break;
|
|
1466
|
+
case "attachment":
|
|
1467
|
+
slash.addAttachmentOption(() => named(new CreateAttachmentOption, name, def));
|
|
1468
|
+
break;
|
|
1469
|
+
case "channel": {
|
|
1470
|
+
const config = def.config;
|
|
1471
|
+
const channel = named(new CreateChannelOption, name, def);
|
|
1472
|
+
if (config.kinds?.length)
|
|
1473
|
+
channel.addChannelTypes(...channelTypes(config.kinds));
|
|
1474
|
+
slash.addChannelOption(() => channel);
|
|
1475
|
+
break;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
var PREFIX_TYPES = {
|
|
1480
|
+
string: "string",
|
|
1481
|
+
integer: "integer",
|
|
1482
|
+
number: "number",
|
|
1483
|
+
boolean: "boolean",
|
|
1484
|
+
user: "user",
|
|
1485
|
+
role: "role",
|
|
1486
|
+
channel: "channel",
|
|
1487
|
+
mentionable: "mentionable",
|
|
1488
|
+
attachment: null
|
|
1489
|
+
};
|
|
1490
|
+
function prefixSpecs(options) {
|
|
1491
|
+
const entries = Object.entries(options);
|
|
1492
|
+
const specs = [];
|
|
1493
|
+
for (const [index, [name, def]] of entries.entries()) {
|
|
1494
|
+
const type = PREFIX_TYPES[def.kind];
|
|
1495
|
+
if (type === null)
|
|
1496
|
+
continue;
|
|
1497
|
+
const config = def.config;
|
|
1498
|
+
const choices = (def.words ?? config.choices)?.map((choice) => typeof choice === "object" ? choice.value : choice);
|
|
1499
|
+
specs.push({
|
|
1500
|
+
name,
|
|
1501
|
+
type: type === "string" && index === entries.length - 1 ? "rest" : type,
|
|
1502
|
+
required: settings(def).required === true && config.default === undefined,
|
|
1503
|
+
min: config.min,
|
|
1504
|
+
max: config.max,
|
|
1505
|
+
maxLength: def.kind === "string" ? config.max : undefined,
|
|
1506
|
+
choices
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
return specs;
|
|
1510
|
+
}
|
|
1511
|
+
function command(definition) {
|
|
1512
|
+
const slash = definition.slash ?? true;
|
|
1513
|
+
const prefix = definition.prefix ? {
|
|
1514
|
+
aliases: typeof definition.prefix === "object" ? [...definition.prefix.aliases ?? []] : []
|
|
1515
|
+
} : false;
|
|
1516
|
+
if (!COMMAND_NAME.test(definition.name))
|
|
1517
|
+
throw new RangeError(`Invalid command name: ${definition.name}. Use 1-32 lowercase letters, digits, - or _.`);
|
|
1518
|
+
if (definition.description.length < 1 || definition.description.length > 100)
|
|
1519
|
+
throw new RangeError("A command description must be 1-100 characters.");
|
|
1520
|
+
if (!slash && !prefix)
|
|
1521
|
+
throw new TypeError(`Command ${definition.name} is neither a slash nor a prefix command.`);
|
|
1522
|
+
for (const alias of prefix ? prefix.aliases : [])
|
|
1523
|
+
if (!COMMAND_NAME.test(alias))
|
|
1524
|
+
throw new RangeError(`Invalid alias for ${definition.name}: ${alias}.`);
|
|
1525
|
+
const options = definition.options ?? {};
|
|
1526
|
+
let optionalSeen;
|
|
1527
|
+
for (const [name, def] of Object.entries(options)) {
|
|
1528
|
+
const needed = settings(def).required === true;
|
|
1529
|
+
if (needed && optionalSeen !== undefined)
|
|
1530
|
+
throw new TypeError(`Option ${name} is required but follows the optional option ${optionalSeen}; put required options first.`);
|
|
1531
|
+
if (!needed)
|
|
1532
|
+
optionalSeen ??= name;
|
|
1533
|
+
}
|
|
1534
|
+
const permissions = definition.permissions ?? [];
|
|
1535
|
+
const guildOnly = definition.guildOnly ?? permissions.length > 0;
|
|
1536
|
+
const toJSON = () => {
|
|
1537
|
+
const builder = new CreateSlashCommand().setName(definition.name).setDescription(definition.description);
|
|
1538
|
+
for (const [name, def] of Object.entries(options))
|
|
1539
|
+
addOptionTo(builder, name, def);
|
|
1540
|
+
if (permissions.length)
|
|
1541
|
+
builder.setDefaultMemberPermissions(new PermissionSet([...permissions]).bitfield);
|
|
1542
|
+
if (guildOnly)
|
|
1543
|
+
builder.setContexts(0);
|
|
1544
|
+
if (definition.nsfw)
|
|
1545
|
+
builder.setNSFW(true);
|
|
1546
|
+
return builder.toJSON();
|
|
1547
|
+
};
|
|
1548
|
+
if (slash)
|
|
1549
|
+
toJSON();
|
|
1550
|
+
return Object.freeze({
|
|
1551
|
+
name: definition.name,
|
|
1552
|
+
description: definition.description,
|
|
1553
|
+
options,
|
|
1554
|
+
permissions,
|
|
1555
|
+
guildOnly,
|
|
1556
|
+
nsfw: definition.nsfw ?? false,
|
|
1557
|
+
slash,
|
|
1558
|
+
prefix,
|
|
1559
|
+
run: definition.run,
|
|
1560
|
+
toJSON,
|
|
1561
|
+
usage(prefixText) {
|
|
1562
|
+
const parts = Object.entries(options).map(([name, def]) => {
|
|
1563
|
+
const required = settings(def).required === true && settings(def).default === undefined;
|
|
1564
|
+
const label = def.kind === "attachment" ? `${name}\uD83D\uDCCE` : name;
|
|
1565
|
+
return required ? `<${label}>` : `[${label}]`;
|
|
1566
|
+
});
|
|
1567
|
+
return [`${prefixText}${definition.name}`, ...parts].join(" ");
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
function applyDefault(def, value) {
|
|
1572
|
+
if (value !== null && value !== undefined)
|
|
1573
|
+
return value;
|
|
1574
|
+
return settings(def).default;
|
|
1575
|
+
}
|
|
1576
|
+
function readSlashOptions(options, interaction) {
|
|
1577
|
+
const values = {};
|
|
1578
|
+
for (const [name, def] of Object.entries(options)) {
|
|
1579
|
+
const source = interaction.options;
|
|
1580
|
+
let value;
|
|
1581
|
+
switch (def.kind) {
|
|
1582
|
+
case "string":
|
|
1583
|
+
value = source.getString(name);
|
|
1584
|
+
break;
|
|
1585
|
+
case "integer":
|
|
1586
|
+
value = source.getInteger(name);
|
|
1587
|
+
break;
|
|
1588
|
+
case "number":
|
|
1589
|
+
value = source.getNumber(name);
|
|
1590
|
+
break;
|
|
1591
|
+
case "boolean":
|
|
1592
|
+
value = source.getBoolean(name);
|
|
1593
|
+
break;
|
|
1594
|
+
case "user":
|
|
1595
|
+
value = idOf(source.getUser(name));
|
|
1596
|
+
break;
|
|
1597
|
+
case "role":
|
|
1598
|
+
value = idOf(source.getRole(name));
|
|
1599
|
+
break;
|
|
1600
|
+
case "channel":
|
|
1601
|
+
value = idOf(source.getChannel(name));
|
|
1602
|
+
break;
|
|
1603
|
+
case "mentionable": {
|
|
1604
|
+
const id = idOf(source.getMentionable(name));
|
|
1605
|
+
value = id ? { id, type: source.getMentionableType(name) ?? "user" } : null;
|
|
1606
|
+
break;
|
|
1607
|
+
}
|
|
1608
|
+
case "attachment":
|
|
1609
|
+
value = source.getAttachment(name);
|
|
1610
|
+
break;
|
|
1611
|
+
}
|
|
1612
|
+
values[name] = applyDefault(def, value);
|
|
1613
|
+
}
|
|
1614
|
+
return values;
|
|
1615
|
+
}
|
|
1616
|
+
function idOf(record) {
|
|
1617
|
+
return record === null ? null : String(record.id);
|
|
1618
|
+
}
|
|
1619
|
+
function words(name) {
|
|
1620
|
+
return name.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
class CommandRegistry {
|
|
1624
|
+
#bot;
|
|
1625
|
+
#commands = new Map;
|
|
1626
|
+
#names = new Map;
|
|
1627
|
+
#listening = false;
|
|
1628
|
+
constructor(bot) {
|
|
1629
|
+
this.#bot = bot;
|
|
1630
|
+
}
|
|
1631
|
+
add(...commands) {
|
|
1632
|
+
for (const added of commands) {
|
|
1633
|
+
const taken = [
|
|
1634
|
+
added.name,
|
|
1635
|
+
...added.prefix ? added.prefix.aliases : []
|
|
1636
|
+
];
|
|
1637
|
+
for (const name of taken) {
|
|
1638
|
+
const owner = this.#names.get(name);
|
|
1639
|
+
if (owner && owner.name !== added.name)
|
|
1640
|
+
throw new TypeError(`The name "${name}" is already used by the ${owner.name} command.`);
|
|
1641
|
+
}
|
|
1642
|
+
const previous = this.#commands.get(added.name);
|
|
1643
|
+
if (previous)
|
|
1644
|
+
for (const name of [
|
|
1645
|
+
previous.name,
|
|
1646
|
+
...previous.prefix ? previous.prefix.aliases : []
|
|
1647
|
+
])
|
|
1648
|
+
this.#names.delete(name);
|
|
1649
|
+
this.#commands.set(added.name, added);
|
|
1650
|
+
if (added.slash || added.prefix)
|
|
1651
|
+
for (const name of taken)
|
|
1652
|
+
this.#names.set(name, added);
|
|
1653
|
+
}
|
|
1654
|
+
return this;
|
|
1655
|
+
}
|
|
1656
|
+
get(name) {
|
|
1657
|
+
return this.#names.get(name.toLowerCase());
|
|
1658
|
+
}
|
|
1659
|
+
list() {
|
|
1660
|
+
return [...this.#commands.values()];
|
|
1661
|
+
}
|
|
1662
|
+
async deploy(options = {}) {
|
|
1663
|
+
if (!this.#bot.isReady())
|
|
1664
|
+
throw new Error('Deploy commands after the client is ready: bot.once("ready", () => bot.commands.deploy()).');
|
|
1665
|
+
const payloads = this.list().filter((entry) => entry.slash).map((entry) => entry.toJSON());
|
|
1666
|
+
await (options.guildId === undefined ? this.#bot.application.commands.set(payloads) : this.#bot.application.commands.setGuild(options.guildId, payloads));
|
|
1667
|
+
return payloads.length;
|
|
1668
|
+
}
|
|
1669
|
+
listen(options = {}) {
|
|
1670
|
+
if (this.#listening)
|
|
1671
|
+
throw new TypeError("bot.commands.listen() was already called.");
|
|
1672
|
+
this.#listening = true;
|
|
1673
|
+
const prefixes = options.prefix === undefined ? [] : typeof options.prefix === "string" ? [options.prefix] : [...options.prefix];
|
|
1674
|
+
if (prefixes.some((prefix) => prefix === ""))
|
|
1675
|
+
throw new TypeError("A command prefix cannot be empty.");
|
|
1676
|
+
this.#bot.on("interactionCreate", async (interaction) => {
|
|
1677
|
+
if (!interaction.isChatInputCommand())
|
|
1678
|
+
return;
|
|
1679
|
+
const found = this.#commands.get(interaction.commandName);
|
|
1680
|
+
if (found?.slash)
|
|
1681
|
+
await this.#runSlash(found, interaction);
|
|
1682
|
+
});
|
|
1683
|
+
if (prefixes.length) {
|
|
1684
|
+
this.#warnAboutIntents();
|
|
1685
|
+
this.#bot.on("messageCreate", async (message) => {
|
|
1686
|
+
if (message.author.bot)
|
|
1687
|
+
return;
|
|
1688
|
+
const prefix = prefixes.find((p) => message.content.startsWith(p));
|
|
1689
|
+
if (prefix !== undefined)
|
|
1690
|
+
await this.#runPrefix(message, prefix);
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
return this;
|
|
1694
|
+
}
|
|
1695
|
+
#warnAboutIntents() {
|
|
1696
|
+
const intents = resolveGatewayIntents(this.#bot.options.intents);
|
|
1697
|
+
const missing = [];
|
|
1698
|
+
if ((intents & 1 << 15) === 0)
|
|
1699
|
+
missing.push("MessageContent");
|
|
1700
|
+
if ((intents & (1 << 9 | 1 << 12)) === 0)
|
|
1701
|
+
missing.push("GuildMessages or DirectMessages");
|
|
1702
|
+
if (missing.length === 0)
|
|
1703
|
+
return;
|
|
1704
|
+
process.emitWarning(`Prefix commands need the ${missing.join(" and ")} intent${missing.length > 1 ? "s" : ""}; without ${missing.length > 1 ? "them" : "it"} Discord sends empty message content and no prefix command will match.`, { type: "LunibeeWarning", code: "LUNIBEE_MESSAGE_CONTENT_INTENT" });
|
|
1705
|
+
}
|
|
1706
|
+
async#runSlash(found, interaction) {
|
|
1707
|
+
let answered = false;
|
|
1708
|
+
const reply = async (content) => {
|
|
1709
|
+
const body = typeof content === "string" ? { content } : content;
|
|
1710
|
+
if (answered)
|
|
1711
|
+
await interaction.followUp(body);
|
|
1712
|
+
else if (interaction.deferred)
|
|
1713
|
+
await interaction.editReply(body);
|
|
1714
|
+
else
|
|
1715
|
+
await interaction.reply(body);
|
|
1716
|
+
answered = true;
|
|
1717
|
+
};
|
|
1718
|
+
await found.run({
|
|
1719
|
+
bot: this.#bot,
|
|
1720
|
+
options: readSlashOptions(found.options, interaction),
|
|
1721
|
+
source: "slash",
|
|
1722
|
+
guildId: interaction.guildId,
|
|
1723
|
+
channelId: interaction.channelId,
|
|
1724
|
+
userId: interaction.user?.id ?? "",
|
|
1725
|
+
member: interaction.member,
|
|
1726
|
+
interaction,
|
|
1727
|
+
message: undefined,
|
|
1728
|
+
reply,
|
|
1729
|
+
defer: async (deferOptions) => {
|
|
1730
|
+
await interaction.deferReply({
|
|
1731
|
+
ephemeral: deferOptions?.ephemeral ?? false
|
|
1732
|
+
});
|
|
1733
|
+
}
|
|
1734
|
+
});
|
|
1735
|
+
}
|
|
1736
|
+
async#runPrefix(message, prefix) {
|
|
1737
|
+
const text = message.content.slice(prefix.length).trim();
|
|
1738
|
+
const [name = "", ...rest] = text.split(/\s+/);
|
|
1739
|
+
const found = this.get(name);
|
|
1740
|
+
if (!found?.prefix)
|
|
1741
|
+
return;
|
|
1742
|
+
const reply = async (content) => {
|
|
1743
|
+
const { ephemeral: _ephemeral, ...body } = typeof content === "string" ? { content } : content;
|
|
1744
|
+
await message.reply(body);
|
|
1745
|
+
};
|
|
1746
|
+
if (found.guildOnly && !message.guildId) {
|
|
1747
|
+
await reply("This command only works in servers.");
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
if (found.permissions.length) {
|
|
1751
|
+
const lacking = found.permissions.filter((permission) => !message.member?.permissions.has(permission));
|
|
1752
|
+
if (lacking.length) {
|
|
1753
|
+
await reply(`You need ${lacking.map((p) => `**${words(p)}**`).join(", ")}.`);
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
const parsed = parsePrefixArgs(rest.join(" "), prefixSpecs(found.options));
|
|
1758
|
+
const attachments = [...message.attachments];
|
|
1759
|
+
const values = {};
|
|
1760
|
+
if (parsed.ok)
|
|
1761
|
+
for (const [key, def] of Object.entries(found.options)) {
|
|
1762
|
+
if (def.kind === "attachment") {
|
|
1763
|
+
const attachment = attachments.shift();
|
|
1764
|
+
if (!attachment && settings(def).required === true) {
|
|
1765
|
+
await reply(`\`${key}\` is required. Usage: \`${found.usage(prefix)}\``);
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
values[key] = applyDefault(def, attachment);
|
|
1769
|
+
} else
|
|
1770
|
+
values[key] = applyDefault(def, parsed.values[key]);
|
|
1771
|
+
}
|
|
1772
|
+
else {
|
|
1773
|
+
await reply(`\`${parsed.arg}\` ${parsed.error}. Usage: \`${found.usage(prefix)}\``);
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
await found.run({
|
|
1777
|
+
bot: this.#bot,
|
|
1778
|
+
options: values,
|
|
1779
|
+
source: "prefix",
|
|
1780
|
+
guildId: message.guildId,
|
|
1781
|
+
channelId: message.channelId,
|
|
1782
|
+
userId: message.author.id,
|
|
1783
|
+
member: message.member ?? null,
|
|
1784
|
+
interaction: undefined,
|
|
1785
|
+
message,
|
|
1786
|
+
reply,
|
|
1787
|
+
defer: async () => {}
|
|
1788
|
+
});
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
// packages/core/src/channel-create.ts
|
|
1792
|
+
var CREATABLE = [
|
|
1793
|
+
"text",
|
|
1794
|
+
"announcement",
|
|
1795
|
+
"voice",
|
|
1796
|
+
"stage",
|
|
1797
|
+
"category",
|
|
1798
|
+
"forum",
|
|
1799
|
+
"media"
|
|
1800
|
+
];
|
|
1801
|
+
function emoji(value) {
|
|
1802
|
+
return /^\d+$/.test(value) ? { emoji_id: value, emoji_name: null } : { emoji_id: null, emoji_name: value };
|
|
1803
|
+
}
|
|
1804
|
+
function channelCreatePayload(options) {
|
|
1805
|
+
if (!CREATABLE.includes(options.kind))
|
|
1806
|
+
throw new TypeError(`Cannot create a ${String(options.kind)} channel here. Use one of: ${CREATABLE.join(", ")}.`);
|
|
1807
|
+
if (options.name.length < 1 || options.name.length > 100)
|
|
1808
|
+
throw new RangeError("A channel name must be 1-100 characters.");
|
|
1809
|
+
const body = {
|
|
1810
|
+
name: options.name,
|
|
1811
|
+
type: ChannelKinds[options.kind][0],
|
|
1812
|
+
parent_id: options.parent,
|
|
1813
|
+
position: options.position,
|
|
1814
|
+
permission_overwrites: options.permissionOverwrites,
|
|
1815
|
+
reason: options.reason
|
|
1816
|
+
};
|
|
1817
|
+
switch (options.kind) {
|
|
1818
|
+
case "text":
|
|
1819
|
+
case "announcement":
|
|
1820
|
+
case "forum":
|
|
1821
|
+
case "media": {
|
|
1822
|
+
if (options.slowmode !== undefined && (!Number.isInteger(options.slowmode) || options.slowmode < 0 || options.slowmode > 21600))
|
|
1823
|
+
throw new RangeError("slowmode must be 0-21600 seconds.");
|
|
1824
|
+
body.topic = options.topic;
|
|
1825
|
+
body.nsfw = options.nsfw;
|
|
1826
|
+
body.rate_limit_per_user = options.slowmode;
|
|
1827
|
+
body.default_auto_archive_duration = options.autoArchive;
|
|
1828
|
+
if (options.kind === "forum" || options.kind === "media") {
|
|
1829
|
+
body.default_thread_rate_limit_per_user = options.threadSlowmode;
|
|
1830
|
+
body.available_tags = options.tags?.map((tag) => ({
|
|
1831
|
+
name: tag.name,
|
|
1832
|
+
moderated: tag.moderated ?? false,
|
|
1833
|
+
...tag.emoji ? emoji(tag.emoji) : {}
|
|
1834
|
+
}));
|
|
1835
|
+
if (options.defaultReaction)
|
|
1836
|
+
body.default_reaction_emoji = emoji(options.defaultReaction);
|
|
1837
|
+
if (options.sortOrder)
|
|
1838
|
+
body.default_sort_order = options.sortOrder === "latest-activity" ? 0 : 1;
|
|
1839
|
+
if (options.layout)
|
|
1840
|
+
body.default_forum_layout = options.layout === "list" ? 1 : 2;
|
|
1841
|
+
}
|
|
1842
|
+
break;
|
|
1843
|
+
}
|
|
1844
|
+
case "voice":
|
|
1845
|
+
case "stage":
|
|
1846
|
+
if (options.userLimit !== undefined && (!Number.isInteger(options.userLimit) || options.userLimit < 0 || options.userLimit > 99))
|
|
1847
|
+
throw new RangeError("userLimit must be 0-99.");
|
|
1848
|
+
body.bitrate = options.bitrate;
|
|
1849
|
+
body.user_limit = options.userLimit;
|
|
1850
|
+
body.rtc_region = options.region;
|
|
1851
|
+
body.nsfw = options.nsfw;
|
|
1852
|
+
if (options.videoQuality)
|
|
1853
|
+
body.video_quality_mode = options.videoQuality === "auto" ? 1 : 2;
|
|
1854
|
+
break;
|
|
1855
|
+
case "category":
|
|
1856
|
+
break;
|
|
1857
|
+
}
|
|
1858
|
+
return body;
|
|
1859
|
+
}
|
|
1860
|
+
// packages/core/src/handles.ts
|
|
1861
|
+
var UNIT_MS = {
|
|
1862
|
+
ms: 1,
|
|
1863
|
+
s: 1000,
|
|
1864
|
+
m: 60000,
|
|
1865
|
+
h: 3600000,
|
|
1866
|
+
d: 86400000,
|
|
1867
|
+
w: 604800000
|
|
1868
|
+
};
|
|
1869
|
+
function parseDuration(value) {
|
|
1870
|
+
if (typeof value === "number") {
|
|
1871
|
+
if (!Number.isFinite(value) || value < 0)
|
|
1872
|
+
throw new RangeError("A duration must be a non-negative, finite number of milliseconds.");
|
|
1873
|
+
return value;
|
|
1874
|
+
}
|
|
1875
|
+
const text = value.replace(/\s+/g, "").toLowerCase();
|
|
1876
|
+
if (!/^(?:\d+(?:\.\d+)?(?:ms|s|m|h|d|w))+$/.test(text))
|
|
1877
|
+
throw new RangeError(`Invalid duration: ${JSON.stringify(value)}. Use a number of milliseconds or text such as "90s", "10m" or "1h30m".`);
|
|
1878
|
+
let total = 0;
|
|
1879
|
+
for (const [, amount, unit] of text.matchAll(/(\d+(?:\.\d+)?)(ms|s|m|h|d|w)/g))
|
|
1880
|
+
total += Number(amount) * UNIT_MS[unit];
|
|
1881
|
+
return Math.round(total);
|
|
1882
|
+
}
|
|
1883
|
+
function payload(input) {
|
|
1884
|
+
return typeof input === "string" ? { content: input } : input;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
class UserHandle {
|
|
1888
|
+
bot;
|
|
1889
|
+
id;
|
|
1890
|
+
constructor(bot, id) {
|
|
1891
|
+
this.bot = bot;
|
|
1892
|
+
this.id = id;
|
|
1893
|
+
}
|
|
1894
|
+
peek() {
|
|
1895
|
+
return this.bot.users.get(this.id);
|
|
1896
|
+
}
|
|
1897
|
+
get() {
|
|
1898
|
+
return this.bot.users.resolve(this.id);
|
|
1899
|
+
}
|
|
1900
|
+
fetch() {
|
|
1901
|
+
return this.bot.users.fetch(this.id);
|
|
1902
|
+
}
|
|
1903
|
+
async dm() {
|
|
1904
|
+
const data = await this.bot.users.createDM(this.id);
|
|
1905
|
+
this.bot.channels.upsert(data);
|
|
1906
|
+
return new ChannelHandle(this.bot, data.id);
|
|
1907
|
+
}
|
|
1908
|
+
async send(message) {
|
|
1909
|
+
return (await this.dm()).send(message);
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
class GuildHandle {
|
|
1914
|
+
bot;
|
|
1915
|
+
id;
|
|
1916
|
+
constructor(bot, id) {
|
|
1917
|
+
this.bot = bot;
|
|
1918
|
+
this.id = id;
|
|
1919
|
+
}
|
|
1920
|
+
peek() {
|
|
1921
|
+
return this.bot.guilds.get(this.id);
|
|
1922
|
+
}
|
|
1923
|
+
get() {
|
|
1924
|
+
return this.bot.guilds.resolve(this.id);
|
|
1925
|
+
}
|
|
1926
|
+
fetch() {
|
|
1927
|
+
return this.bot.guilds.fetch(this.id);
|
|
1928
|
+
}
|
|
1929
|
+
get members() {
|
|
1930
|
+
return this.bot.guilds.members(this.id).cache;
|
|
1931
|
+
}
|
|
1932
|
+
get roles() {
|
|
1933
|
+
return this.bot.guilds.roles(this.id).cache;
|
|
1934
|
+
}
|
|
1935
|
+
get channels() {
|
|
1936
|
+
return this.bot.channels.cache.filter((channel) => channel.guildId === this.id);
|
|
1937
|
+
}
|
|
1938
|
+
member(userId) {
|
|
1939
|
+
return new MemberHandle(this.bot, this.id, userId);
|
|
1940
|
+
}
|
|
1941
|
+
role(roleId) {
|
|
1942
|
+
return new RoleHandle(this.bot, this.id, roleId);
|
|
1943
|
+
}
|
|
1944
|
+
channel(channelId) {
|
|
1945
|
+
return new ChannelHandle(this.bot, channelId);
|
|
1946
|
+
}
|
|
1947
|
+
async createChannel(options) {
|
|
1948
|
+
const channel = await this.bot.channels.create(this.id, channelCreatePayload(options));
|
|
1949
|
+
return channel.as(options.kind);
|
|
1950
|
+
}
|
|
1951
|
+
ban(userId, options) {
|
|
1952
|
+
return this.bot.guilds.members(this.id).ban(userId, options);
|
|
1953
|
+
}
|
|
1954
|
+
unban(userId, reason) {
|
|
1955
|
+
return this.bot.guilds.members(this.id).unban(userId, reason);
|
|
1956
|
+
}
|
|
1957
|
+
edit(options) {
|
|
1958
|
+
return this.bot.guilds.edit(this.id, options);
|
|
1959
|
+
}
|
|
1960
|
+
leave() {
|
|
1961
|
+
return this.bot.users.leaveGuild(this.id);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
class MemberHandle {
|
|
1966
|
+
bot;
|
|
1967
|
+
guildId;
|
|
1968
|
+
userId;
|
|
1969
|
+
constructor(bot, guildId, userId) {
|
|
1970
|
+
this.bot = bot;
|
|
1971
|
+
this.guildId = guildId;
|
|
1972
|
+
this.userId = userId;
|
|
1973
|
+
}
|
|
1974
|
+
get members() {
|
|
1975
|
+
return this.bot.guilds.members(this.guildId);
|
|
1976
|
+
}
|
|
1977
|
+
peek() {
|
|
1978
|
+
return this.members.get(this.userId);
|
|
1979
|
+
}
|
|
1980
|
+
get() {
|
|
1981
|
+
return this.members.resolve(this.userId);
|
|
1982
|
+
}
|
|
1983
|
+
fetch() {
|
|
1984
|
+
return this.members.fetch(this.userId);
|
|
1985
|
+
}
|
|
1986
|
+
guild() {
|
|
1987
|
+
return new GuildHandle(this.bot, this.guildId);
|
|
1988
|
+
}
|
|
1989
|
+
user() {
|
|
1990
|
+
return new UserHandle(this.bot, this.userId);
|
|
1991
|
+
}
|
|
1992
|
+
kick(reason) {
|
|
1993
|
+
return this.members.kick(this.userId, reason);
|
|
1994
|
+
}
|
|
1995
|
+
ban(options) {
|
|
1996
|
+
return this.members.ban(this.userId, options);
|
|
1997
|
+
}
|
|
1998
|
+
unban(reason) {
|
|
1999
|
+
return this.members.unban(this.userId, reason);
|
|
2000
|
+
}
|
|
2001
|
+
edit(options) {
|
|
2002
|
+
return this.members.edit(this.userId, options);
|
|
2003
|
+
}
|
|
2004
|
+
addRole(roleId, reason) {
|
|
2005
|
+
return this.members.addRole(this.userId, roleId, reason);
|
|
2006
|
+
}
|
|
2007
|
+
removeRole(roleId, reason) {
|
|
2008
|
+
return this.members.removeRole(this.userId, roleId, reason);
|
|
2009
|
+
}
|
|
2010
|
+
async timeout(duration, reason) {
|
|
2011
|
+
return this.members.timeout(this.userId, duration === null ? null : parseDuration(duration), reason);
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
class RoleHandle {
|
|
2016
|
+
bot;
|
|
2017
|
+
guildId;
|
|
2018
|
+
roleId;
|
|
2019
|
+
constructor(bot, guildId, roleId) {
|
|
2020
|
+
this.bot = bot;
|
|
2021
|
+
this.guildId = guildId;
|
|
2022
|
+
this.roleId = roleId;
|
|
2023
|
+
}
|
|
2024
|
+
get roles() {
|
|
2025
|
+
return this.bot.guilds.roles(this.guildId);
|
|
2026
|
+
}
|
|
2027
|
+
peek() {
|
|
2028
|
+
return this.roles.get(this.roleId);
|
|
2029
|
+
}
|
|
2030
|
+
get() {
|
|
2031
|
+
return this.roles.resolve(this.roleId);
|
|
2032
|
+
}
|
|
2033
|
+
fetch() {
|
|
2034
|
+
return this.roles.fetch(this.roleId);
|
|
2035
|
+
}
|
|
2036
|
+
edit(options) {
|
|
2037
|
+
return this.roles.edit(this.roleId, options);
|
|
2038
|
+
}
|
|
2039
|
+
delete(reason) {
|
|
2040
|
+
return this.roles.remove(this.roleId, reason);
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
class ChannelHandle {
|
|
2045
|
+
bot;
|
|
2046
|
+
id;
|
|
2047
|
+
constructor(bot, id) {
|
|
2048
|
+
this.bot = bot;
|
|
2049
|
+
this.id = id;
|
|
2050
|
+
}
|
|
2051
|
+
peek() {
|
|
2052
|
+
return this.bot.channels.get(this.id);
|
|
2053
|
+
}
|
|
2054
|
+
get() {
|
|
2055
|
+
return this.bot.channels.resolve(this.id);
|
|
2056
|
+
}
|
|
2057
|
+
fetch() {
|
|
2058
|
+
return this.bot.channels.fetch(this.id);
|
|
2059
|
+
}
|
|
2060
|
+
message(messageId) {
|
|
2061
|
+
return new MessageHandle(this.bot, this.id, messageId);
|
|
2062
|
+
}
|
|
2063
|
+
async as(...kinds) {
|
|
2064
|
+
return (await this.get()).as(...kinds);
|
|
2065
|
+
}
|
|
2066
|
+
send(message) {
|
|
2067
|
+
return this.bot.channels.send(this.id, payload(message));
|
|
2068
|
+
}
|
|
2069
|
+
messages(query = {}) {
|
|
2070
|
+
return this.bot.channels.fetchMessages(this.id, query);
|
|
2071
|
+
}
|
|
2072
|
+
edit(options) {
|
|
2073
|
+
return this.bot.channels.edit(this.id, options);
|
|
2074
|
+
}
|
|
2075
|
+
delete(reason) {
|
|
2076
|
+
return this.bot.channels.remove(this.id, reason);
|
|
2077
|
+
}
|
|
2078
|
+
bulkDelete(messageIds, reason) {
|
|
2079
|
+
return this.bot.channels.bulkDeleteMessages(this.id, messageIds, reason);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
class MessageHandle {
|
|
2084
|
+
bot;
|
|
2085
|
+
channelId;
|
|
2086
|
+
messageId;
|
|
2087
|
+
constructor(bot, channelId, messageId) {
|
|
2088
|
+
this.bot = bot;
|
|
2089
|
+
this.channelId = channelId;
|
|
2090
|
+
this.messageId = messageId;
|
|
2091
|
+
}
|
|
2092
|
+
peek() {
|
|
2093
|
+
return this.bot.channels.cachedMessages(this.channelId)?.cache.peek(this.messageId);
|
|
794
2094
|
}
|
|
795
|
-
|
|
796
|
-
return this.
|
|
2095
|
+
async get() {
|
|
2096
|
+
return this.peek() ?? this.fetch();
|
|
797
2097
|
}
|
|
798
|
-
|
|
799
|
-
return this.
|
|
2098
|
+
fetch() {
|
|
2099
|
+
return this.bot.channels.fetchMessage(this.channelId, this.messageId);
|
|
800
2100
|
}
|
|
801
|
-
|
|
802
|
-
return this.
|
|
2101
|
+
channel() {
|
|
2102
|
+
return new ChannelHandle(this.bot, this.channelId);
|
|
803
2103
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
var InteractionResponseEnum = {
|
|
807
|
-
Pong: 1,
|
|
808
|
-
ChannelMessage: 4,
|
|
809
|
-
DeferredChannelMessage: 5,
|
|
810
|
-
DeferredMessageUpdate: 6,
|
|
811
|
-
MessageUpdate: 7,
|
|
812
|
-
Autocomplete: 8,
|
|
813
|
-
Modal: 9
|
|
814
|
-
};
|
|
815
|
-
// packages/collection/src/index.ts
|
|
816
|
-
class RecencyList {
|
|
817
|
-
#nodes = new Map;
|
|
818
|
-
#oldest;
|
|
819
|
-
#newest;
|
|
820
|
-
get size() {
|
|
821
|
-
return this.#nodes.size;
|
|
822
|
-
}
|
|
823
|
-
oldest() {
|
|
824
|
-
return this.#oldest?.key;
|
|
825
|
-
}
|
|
826
|
-
touch(key) {
|
|
827
|
-
const node = this.#nodes.get(key);
|
|
828
|
-
if (node)
|
|
829
|
-
return this.#moveNewest(node);
|
|
830
|
-
const created = { key, older: this.#newest };
|
|
831
|
-
if (this.#newest)
|
|
832
|
-
this.#newest.newer = created;
|
|
833
|
-
else
|
|
834
|
-
this.#oldest = created;
|
|
835
|
-
this.#newest = created;
|
|
836
|
-
this.#nodes.set(key, created);
|
|
2104
|
+
edit(message) {
|
|
2105
|
+
return this.bot.channels.editMessage(this.channelId, this.messageId, typeof message === "string" ? { content: message } : message);
|
|
837
2106
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
2107
|
+
delete(reason) {
|
|
2108
|
+
return this.bot.channels.deleteMessage(this.channelId, this.messageId, reason);
|
|
2109
|
+
}
|
|
2110
|
+
reply(message) {
|
|
2111
|
+
return this.bot.channels.send(this.channelId, {
|
|
2112
|
+
...payload(message),
|
|
2113
|
+
message_reference: {
|
|
2114
|
+
message_id: this.messageId,
|
|
2115
|
+
channel_id: this.channelId
|
|
2116
|
+
}
|
|
2117
|
+
});
|
|
842
2118
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
if (!node)
|
|
846
|
-
return false;
|
|
847
|
-
this.#unlink(node);
|
|
848
|
-
this.#nodes.delete(key);
|
|
849
|
-
return true;
|
|
2119
|
+
react(emoji) {
|
|
2120
|
+
return this.bot.channels.addReaction(this.channelId, this.messageId, emoji);
|
|
850
2121
|
}
|
|
851
|
-
|
|
852
|
-
this
|
|
853
|
-
this.#oldest = this.#newest = undefined;
|
|
2122
|
+
pin(reason) {
|
|
2123
|
+
return this.bot.channels.pinMessage(this.channelId, this.messageId, reason);
|
|
854
2124
|
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
node.older.newer = node.newer;
|
|
858
|
-
else
|
|
859
|
-
this.#oldest = node.newer;
|
|
860
|
-
if (node.newer)
|
|
861
|
-
node.newer.older = node.older;
|
|
862
|
-
else
|
|
863
|
-
this.#newest = node.older;
|
|
864
|
-
node.older = node.newer = undefined;
|
|
2125
|
+
unpin(reason) {
|
|
2126
|
+
return this.bot.channels.unpinMessage(this.channelId, this.messageId, reason);
|
|
865
2127
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
return;
|
|
869
|
-
this.#unlink(node);
|
|
870
|
-
node.older = this.#newest;
|
|
871
|
-
if (this.#newest)
|
|
872
|
-
this.#newest.newer = node;
|
|
873
|
-
else
|
|
874
|
-
this.#oldest = node;
|
|
875
|
-
this.#newest = node;
|
|
2128
|
+
crosspost() {
|
|
2129
|
+
return this.bot.channels.crosspostMessage(this.channelId, this.messageId);
|
|
876
2130
|
}
|
|
877
2131
|
}
|
|
2132
|
+
// packages/collection/src/index.ts
|
|
2133
|
+
function newPolicy(options = {}) {
|
|
2134
|
+
return {
|
|
2135
|
+
ttl: options.ttl,
|
|
2136
|
+
jitter: options.jitter ?? 0,
|
|
2137
|
+
maxSize: options.maxSize,
|
|
2138
|
+
slide: options.slide ?? true,
|
|
2139
|
+
onEvict: options.onEvict,
|
|
2140
|
+
expired: 0,
|
|
2141
|
+
evicted: 0,
|
|
2142
|
+
entries: new Map,
|
|
2143
|
+
oldest: undefined,
|
|
2144
|
+
newest: undefined,
|
|
2145
|
+
lruSize: 0,
|
|
2146
|
+
heap: [],
|
|
2147
|
+
armedFor: Infinity
|
|
2148
|
+
};
|
|
2149
|
+
}
|
|
2150
|
+
function peekOf(collection, key) {
|
|
2151
|
+
return collection instanceof Map ? Map.prototype.get.call(collection, key) : collection.get(key);
|
|
2152
|
+
}
|
|
2153
|
+
var mapGet = Map.prototype.get;
|
|
2154
|
+
var mapHas = Map.prototype.has;
|
|
2155
|
+
function sample(items, amount) {
|
|
2156
|
+
if (!Number.isInteger(amount) || amount < 0)
|
|
2157
|
+
throw new RangeError("amount must be a non-negative integer.");
|
|
2158
|
+
const count = Math.min(amount, items.length);
|
|
2159
|
+
for (let i = 0;i < count; i++) {
|
|
2160
|
+
const j = i + Math.floor(Math.random() * (items.length - i));
|
|
2161
|
+
[items[i], items[j]] = [items[j], items[i]];
|
|
2162
|
+
}
|
|
2163
|
+
items.length = count;
|
|
2164
|
+
return items;
|
|
2165
|
+
}
|
|
878
2166
|
function assertTTL(ttl) {
|
|
879
2167
|
if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))
|
|
880
2168
|
throw new RangeError("TTL must be a positive number, or omitted.");
|
|
881
2169
|
}
|
|
882
2170
|
|
|
883
2171
|
class Collection extends Map {
|
|
884
|
-
#
|
|
885
|
-
#
|
|
886
|
-
#
|
|
887
|
-
#expiry = new Map;
|
|
888
|
-
#lru = new RecencyList;
|
|
889
|
-
#stats = {
|
|
890
|
-
hits: 0,
|
|
891
|
-
misses: 0,
|
|
892
|
-
expired: 0,
|
|
893
|
-
evicted: 0
|
|
894
|
-
};
|
|
895
|
-
#heap = [];
|
|
896
|
-
#timer;
|
|
897
|
-
#armedFor = Infinity;
|
|
2172
|
+
#policy;
|
|
2173
|
+
#hits = 0;
|
|
2174
|
+
#misses = 0;
|
|
898
2175
|
constructor(entries, options = {}) {
|
|
899
2176
|
super();
|
|
900
2177
|
assertTTL(options.ttl);
|
|
2178
|
+
if (options.jitter !== undefined && !(options.jitter >= 0 && options.jitter <= 1))
|
|
2179
|
+
throw new RangeError("jitter must be between 0 and 1.");
|
|
901
2180
|
if (options.maxSize !== undefined && (!Number.isInteger(options.maxSize) || options.maxSize <= 0))
|
|
902
2181
|
throw new RangeError("maxSize must be a positive integer.");
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
this.#onEvict = options.onEvict;
|
|
2182
|
+
if (options.ttl !== undefined || options.jitter !== undefined || options.maxSize !== undefined || options.slide !== undefined || options.onEvict !== undefined)
|
|
2183
|
+
this.#policy = newPolicy(options);
|
|
906
2184
|
if (entries)
|
|
907
2185
|
for (const [key, value] of entries)
|
|
908
2186
|
this.set(key, value);
|
|
909
2187
|
}
|
|
910
2188
|
set(key, value, ttl) {
|
|
2189
|
+
if (ttl === undefined && this.#policy === undefined)
|
|
2190
|
+
return super.set(key, value);
|
|
911
2191
|
assertTTL(ttl);
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
super.set(key, value);
|
|
2192
|
+
let window = ttl ?? this.#policy?.ttl;
|
|
2193
|
+
const jitter = this.#policy?.jitter ?? 0;
|
|
2194
|
+
if (window !== undefined && jitter > 0)
|
|
2195
|
+
window = Math.max(1, window * (1 - jitter * Math.random()));
|
|
917
2196
|
if (window !== undefined)
|
|
918
|
-
this.#
|
|
919
|
-
|
|
920
|
-
|
|
2197
|
+
this.#policy ??= newPolicy();
|
|
2198
|
+
if (!this.#policy)
|
|
2199
|
+
return super.set(key, value);
|
|
2200
|
+
const before = super.size;
|
|
2201
|
+
super.set(key, value);
|
|
2202
|
+
this.#track(key, value, window, super.size !== before);
|
|
921
2203
|
this.#enforceCap();
|
|
922
2204
|
return this;
|
|
923
2205
|
}
|
|
924
2206
|
setWithoutTTL(key, value) {
|
|
925
|
-
if (this.#
|
|
926
|
-
this.#
|
|
927
|
-
if (this.#lru.size > 0)
|
|
928
|
-
this.#lru.delete(key);
|
|
2207
|
+
if (this.#policy)
|
|
2208
|
+
this.#forget(key);
|
|
929
2209
|
super.set(key, value);
|
|
930
2210
|
return this;
|
|
931
2211
|
}
|
|
932
2212
|
get(key) {
|
|
933
|
-
|
|
934
|
-
|
|
2213
|
+
const policy = this.#policy;
|
|
2214
|
+
const entry = policy?.entries.get(key);
|
|
2215
|
+
if (entry === undefined) {
|
|
2216
|
+
const value = mapGet.call(this, key);
|
|
2217
|
+
if (value !== undefined || mapHas.call(this, key)) {
|
|
2218
|
+
this.#hits++;
|
|
2219
|
+
return value;
|
|
2220
|
+
}
|
|
2221
|
+
this.#misses++;
|
|
935
2222
|
return;
|
|
936
2223
|
}
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
|
|
2224
|
+
const timed = entry.window !== 0;
|
|
2225
|
+
const now = timed ? Date.now() : 0;
|
|
2226
|
+
if (timed && entry.deadline <= now) {
|
|
2227
|
+
this.#expire(entry);
|
|
2228
|
+
this.#misses++;
|
|
940
2229
|
return;
|
|
941
2230
|
}
|
|
942
|
-
this.#
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
return value;
|
|
2231
|
+
this.#hits++;
|
|
2232
|
+
if (timed && policy.slide)
|
|
2233
|
+
entry.deadline = now + entry.window;
|
|
2234
|
+
if (entry.inLru)
|
|
2235
|
+
this.#promote(policy, entry);
|
|
2236
|
+
return entry.value;
|
|
2237
|
+
}
|
|
2238
|
+
ensure(key, factory, ttl) {
|
|
2239
|
+
const existing = this.get(key);
|
|
2240
|
+
if (existing !== undefined || super.has(key))
|
|
2241
|
+
return existing;
|
|
2242
|
+
const created = factory(key, this);
|
|
2243
|
+
this.set(key, created, ttl);
|
|
2244
|
+
return created;
|
|
948
2245
|
}
|
|
949
2246
|
peek(key) {
|
|
950
2247
|
if (!this.#expireIfDue(key) && super.has(key)) {
|
|
951
|
-
this.#
|
|
2248
|
+
this.#hits++;
|
|
952
2249
|
return super.get(key);
|
|
953
2250
|
}
|
|
954
|
-
this.#
|
|
2251
|
+
this.#misses++;
|
|
955
2252
|
return;
|
|
956
2253
|
}
|
|
957
2254
|
get stats() {
|
|
958
|
-
return {
|
|
2255
|
+
return {
|
|
2256
|
+
hits: this.#hits,
|
|
2257
|
+
misses: this.#misses,
|
|
2258
|
+
expired: this.#policy?.expired ?? 0,
|
|
2259
|
+
evicted: this.#policy?.evicted ?? 0
|
|
2260
|
+
};
|
|
959
2261
|
}
|
|
960
2262
|
has(key) {
|
|
961
2263
|
return !this.#expireIfDue(key) && super.has(key);
|
|
@@ -963,19 +2265,23 @@ class Collection extends Map {
|
|
|
963
2265
|
delete(key) {
|
|
964
2266
|
if (this.#expireIfDue(key))
|
|
965
2267
|
return false;
|
|
966
|
-
this.#
|
|
967
|
-
|
|
2268
|
+
if (this.#policy)
|
|
2269
|
+
this.#forget(key);
|
|
968
2270
|
return super.delete(key);
|
|
969
2271
|
}
|
|
970
2272
|
clear() {
|
|
971
2273
|
super.clear();
|
|
972
|
-
this.#
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
2274
|
+
const policy = this.#policy;
|
|
2275
|
+
if (!policy)
|
|
2276
|
+
return;
|
|
2277
|
+
policy.entries.clear();
|
|
2278
|
+
policy.oldest = policy.newest = undefined;
|
|
2279
|
+
policy.lruSize = 0;
|
|
2280
|
+
policy.heap.length = 0;
|
|
2281
|
+
if (policy.timer)
|
|
2282
|
+
clearTimeout(policy.timer);
|
|
2283
|
+
policy.timer = undefined;
|
|
2284
|
+
policy.armedFor = Infinity;
|
|
979
2285
|
}
|
|
980
2286
|
get size() {
|
|
981
2287
|
this.purge();
|
|
@@ -1003,11 +2309,11 @@ class Collection extends Map {
|
|
|
1003
2309
|
ttlRemaining(key) {
|
|
1004
2310
|
if (this.#expireIfDue(key))
|
|
1005
2311
|
return;
|
|
1006
|
-
const
|
|
1007
|
-
return
|
|
2312
|
+
const entry = this.#policy?.entries.get(key);
|
|
2313
|
+
return entry && entry.window !== 0 ? Math.max(0, entry.deadline - Date.now()) : undefined;
|
|
1008
2314
|
}
|
|
1009
2315
|
purge() {
|
|
1010
|
-
if (this.#
|
|
2316
|
+
if (!this.#policy || this.#policy.heap.length === 0)
|
|
1011
2317
|
return 0;
|
|
1012
2318
|
const now = Date.now();
|
|
1013
2319
|
let removed = 0;
|
|
@@ -1018,133 +2324,255 @@ class Collection extends Map {
|
|
|
1018
2324
|
this.#remove(due.key);
|
|
1019
2325
|
removed++;
|
|
1020
2326
|
}
|
|
1021
|
-
this.#
|
|
2327
|
+
this.#policy.expired += removed;
|
|
1022
2328
|
this.#rearm();
|
|
1023
2329
|
for (const [key, value] of dropped)
|
|
1024
2330
|
this.#notify(key, value, "expired");
|
|
1025
2331
|
return removed;
|
|
1026
2332
|
}
|
|
1027
2333
|
#expireIfDue(key) {
|
|
1028
|
-
const
|
|
1029
|
-
if (!
|
|
2334
|
+
const entry = this.#policy?.entries.get(key);
|
|
2335
|
+
if (!entry || entry.window === 0 || entry.deadline > Date.now())
|
|
1030
2336
|
return false;
|
|
1031
|
-
|
|
1032
|
-
this.#remove(key);
|
|
1033
|
-
this.#stats.expired++;
|
|
1034
|
-
this.#notify(key, value, "expired");
|
|
2337
|
+
this.#expire(entry);
|
|
1035
2338
|
return true;
|
|
1036
2339
|
}
|
|
2340
|
+
#expire(entry) {
|
|
2341
|
+
const value = super.get(entry.key);
|
|
2342
|
+
this.#remove(entry.key);
|
|
2343
|
+
this.#policy.expired++;
|
|
2344
|
+
this.#notify(entry.key, value, "expired");
|
|
2345
|
+
}
|
|
1037
2346
|
#remove(key) {
|
|
1038
|
-
this.#
|
|
1039
|
-
this.#lru.delete(key);
|
|
2347
|
+
this.#forget(key);
|
|
1040
2348
|
super.delete(key);
|
|
1041
2349
|
}
|
|
2350
|
+
#forget(key) {
|
|
2351
|
+
const policy = this.#policy;
|
|
2352
|
+
const entry = policy.entries.get(key);
|
|
2353
|
+
if (!entry)
|
|
2354
|
+
return;
|
|
2355
|
+
if (entry.inLru)
|
|
2356
|
+
this.#unlink(policy, entry);
|
|
2357
|
+
policy.entries.delete(key);
|
|
2358
|
+
}
|
|
2359
|
+
#track(key, value, window, isNew) {
|
|
2360
|
+
const policy = this.#policy;
|
|
2361
|
+
const lru = policy.maxSize !== undefined;
|
|
2362
|
+
let entry = isNew ? undefined : policy.entries.get(key);
|
|
2363
|
+
if (entry)
|
|
2364
|
+
entry.value = value;
|
|
2365
|
+
if (window === undefined) {
|
|
2366
|
+
if (entry && entry.window !== 0) {
|
|
2367
|
+
if (lru)
|
|
2368
|
+
entry = this.#replace(policy, entry, 0, 0);
|
|
2369
|
+
else {
|
|
2370
|
+
this.#forget(key);
|
|
2371
|
+
return;
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
if (!entry && lru) {
|
|
2375
|
+
entry = this.#create(key, value, 0, 0);
|
|
2376
|
+
policy.entries.set(key, entry);
|
|
2377
|
+
}
|
|
2378
|
+
if (entry)
|
|
2379
|
+
this.#promote(policy, entry);
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
const deadline = Date.now() + window;
|
|
2383
|
+
if (entry && entry.window !== 0) {
|
|
2384
|
+
entry.deadline = deadline;
|
|
2385
|
+
entry.window = window;
|
|
2386
|
+
if (deadline < entry.filed)
|
|
2387
|
+
entry = this.#replace(policy, entry, window, deadline);
|
|
2388
|
+
else {
|
|
2389
|
+
if (entry.inLru)
|
|
2390
|
+
this.#promote(policy, entry);
|
|
2391
|
+
return;
|
|
2392
|
+
}
|
|
2393
|
+
} else if (entry) {
|
|
2394
|
+
entry.window = window;
|
|
2395
|
+
entry.deadline = entry.filed = deadline;
|
|
2396
|
+
} else {
|
|
2397
|
+
entry = this.#create(key, value, window, deadline);
|
|
2398
|
+
policy.entries.set(key, entry);
|
|
2399
|
+
}
|
|
2400
|
+
if (lru)
|
|
2401
|
+
this.#promote(policy, entry);
|
|
2402
|
+
this.#heapPush(entry);
|
|
2403
|
+
if (policy.heap.length > 2 * policy.entries.size + 8)
|
|
2404
|
+
this.#compact();
|
|
2405
|
+
if (policy.timer === undefined || deadline < policy.armedFor)
|
|
2406
|
+
this.#rearm();
|
|
2407
|
+
}
|
|
2408
|
+
#create(key, value, window, deadline) {
|
|
2409
|
+
return {
|
|
2410
|
+
key,
|
|
2411
|
+
value,
|
|
2412
|
+
older: undefined,
|
|
2413
|
+
newer: undefined,
|
|
2414
|
+
inLru: false,
|
|
2415
|
+
window,
|
|
2416
|
+
deadline,
|
|
2417
|
+
filed: deadline
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
#replace(policy, old, window, deadline) {
|
|
2421
|
+
const entry = {
|
|
2422
|
+
...old,
|
|
2423
|
+
window,
|
|
2424
|
+
deadline,
|
|
2425
|
+
filed: deadline
|
|
2426
|
+
};
|
|
2427
|
+
if (old.inLru) {
|
|
2428
|
+
if (old.older)
|
|
2429
|
+
old.older.newer = entry;
|
|
2430
|
+
else
|
|
2431
|
+
policy.oldest = entry;
|
|
2432
|
+
if (old.newer)
|
|
2433
|
+
old.newer.older = entry;
|
|
2434
|
+
else
|
|
2435
|
+
policy.newest = entry;
|
|
2436
|
+
}
|
|
2437
|
+
policy.entries.set(old.key, entry);
|
|
2438
|
+
return entry;
|
|
2439
|
+
}
|
|
2440
|
+
#promote(policy, entry) {
|
|
2441
|
+
if (entry === policy.newest)
|
|
2442
|
+
return;
|
|
2443
|
+
if (entry.inLru)
|
|
2444
|
+
this.#unlink(policy, entry, true);
|
|
2445
|
+
else {
|
|
2446
|
+
entry.inLru = true;
|
|
2447
|
+
policy.lruSize++;
|
|
2448
|
+
}
|
|
2449
|
+
entry.older = policy.newest;
|
|
2450
|
+
entry.newer = undefined;
|
|
2451
|
+
if (policy.newest)
|
|
2452
|
+
policy.newest.newer = entry;
|
|
2453
|
+
else
|
|
2454
|
+
policy.oldest = entry;
|
|
2455
|
+
policy.newest = entry;
|
|
2456
|
+
}
|
|
2457
|
+
#unlink(policy, entry, keepCount = false) {
|
|
2458
|
+
if (entry.older)
|
|
2459
|
+
entry.older.newer = entry.newer;
|
|
2460
|
+
else
|
|
2461
|
+
policy.oldest = entry.newer;
|
|
2462
|
+
if (entry.newer)
|
|
2463
|
+
entry.newer.older = entry.older;
|
|
2464
|
+
else
|
|
2465
|
+
policy.newest = entry.older;
|
|
2466
|
+
entry.older = entry.newer = undefined;
|
|
2467
|
+
if (!keepCount) {
|
|
2468
|
+
entry.inLru = false;
|
|
2469
|
+
policy.lruSize--;
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
#derived() {
|
|
2473
|
+
const Species = this.constructor[Symbol.species] ?? Collection;
|
|
2474
|
+
return new Species;
|
|
2475
|
+
}
|
|
1042
2476
|
#notify(key, value, reason) {
|
|
1043
|
-
|
|
2477
|
+
const onEvict = this.#policy?.onEvict;
|
|
2478
|
+
if (!onEvict)
|
|
1044
2479
|
return;
|
|
1045
2480
|
try {
|
|
1046
|
-
|
|
2481
|
+
onEvict(key, value, reason);
|
|
1047
2482
|
} catch {}
|
|
1048
2483
|
}
|
|
1049
2484
|
#enforceCap() {
|
|
1050
|
-
|
|
2485
|
+
const policy = this.#policy;
|
|
2486
|
+
const max = policy.maxSize;
|
|
2487
|
+
if (max === undefined)
|
|
1051
2488
|
return;
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
this.#
|
|
2489
|
+
if (policy.lruSize > max && policy.heap.length > 0 && policy.heap[0].filed <= Date.now())
|
|
2490
|
+
this.purge();
|
|
2491
|
+
while (policy.lruSize > max) {
|
|
2492
|
+
const oldest = policy.oldest;
|
|
2493
|
+
const value = policy.onEvict ? super.get(oldest.key) : undefined;
|
|
2494
|
+
this.#unlink(policy, oldest);
|
|
2495
|
+
policy.entries.delete(oldest.key);
|
|
2496
|
+
super.delete(oldest.key);
|
|
2497
|
+
policy.evicted++;
|
|
2498
|
+
this.#notify(oldest.key, value, "evicted");
|
|
1058
2499
|
}
|
|
1059
2500
|
}
|
|
1060
|
-
#schedule(key, window) {
|
|
1061
|
-
const deadline = Date.now() + window;
|
|
1062
|
-
const expiry = this.#expiry.get(key);
|
|
1063
|
-
if (expiry) {
|
|
1064
|
-
expiry.deadline = deadline;
|
|
1065
|
-
expiry.window = window;
|
|
1066
|
-
if (deadline >= expiry.filed)
|
|
1067
|
-
return;
|
|
1068
|
-
expiry.filed = deadline;
|
|
1069
|
-
} else
|
|
1070
|
-
this.#expiry.set(key, { deadline, window, filed: deadline });
|
|
1071
|
-
this.#heapPush({ key, deadline });
|
|
1072
|
-
if (this.#heap.length > 2 * this.#expiry.size + 8)
|
|
1073
|
-
this.#compact();
|
|
1074
|
-
this.#rearm();
|
|
1075
|
-
}
|
|
1076
2501
|
#nextDeadline() {
|
|
2502
|
+
const policy = this.#policy;
|
|
1077
2503
|
for (;; ) {
|
|
1078
|
-
const top =
|
|
2504
|
+
const top = policy.heap[0];
|
|
1079
2505
|
if (top === undefined)
|
|
1080
2506
|
return Infinity;
|
|
1081
|
-
|
|
1082
|
-
if (!expiry || expiry.filed !== top.deadline) {
|
|
2507
|
+
if (policy.entries.get(top.key) !== top) {
|
|
1083
2508
|
this.#heapPop();
|
|
1084
2509
|
continue;
|
|
1085
2510
|
}
|
|
1086
|
-
if (
|
|
1087
|
-
return top.
|
|
2511
|
+
if (top.deadline === top.filed)
|
|
2512
|
+
return top.filed;
|
|
1088
2513
|
this.#heapPop();
|
|
1089
|
-
|
|
1090
|
-
this.#heapPush(
|
|
2514
|
+
top.filed = top.deadline;
|
|
2515
|
+
this.#heapPush(top);
|
|
1091
2516
|
}
|
|
1092
2517
|
}
|
|
1093
2518
|
#compact() {
|
|
1094
|
-
const
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
2519
|
+
const policy = this.#policy;
|
|
2520
|
+
const live = policy.heap.filter((entry) => policy.entries.get(entry.key) === entry);
|
|
2521
|
+
policy.heap.length = 0;
|
|
2522
|
+
for (const entry of live)
|
|
2523
|
+
this.#heapPush(entry);
|
|
1098
2524
|
}
|
|
1099
2525
|
#rearm() {
|
|
2526
|
+
const p = this.#policy;
|
|
1100
2527
|
const deadline = this.#nextDeadline();
|
|
1101
|
-
if (
|
|
2528
|
+
if (p.timer !== undefined && deadline >= p.armedFor)
|
|
1102
2529
|
return;
|
|
1103
|
-
if (
|
|
1104
|
-
clearTimeout(
|
|
1105
|
-
|
|
1106
|
-
|
|
2530
|
+
if (p.timer)
|
|
2531
|
+
clearTimeout(p.timer);
|
|
2532
|
+
p.timer = undefined;
|
|
2533
|
+
p.armedFor = deadline;
|
|
1107
2534
|
if (deadline === Infinity)
|
|
1108
2535
|
return;
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
2536
|
+
p.timer = setTimeout(() => {
|
|
2537
|
+
p.timer = undefined;
|
|
2538
|
+
p.armedFor = Infinity;
|
|
1112
2539
|
this.purge();
|
|
1113
2540
|
}, Math.max(0, deadline - Date.now()));
|
|
1114
|
-
|
|
2541
|
+
p.timer.unref?.();
|
|
1115
2542
|
}
|
|
1116
|
-
#heapPush(
|
|
1117
|
-
const heap = this.#heap;
|
|
1118
|
-
heap.
|
|
1119
|
-
|
|
2543
|
+
#heapPush(entry) {
|
|
2544
|
+
const heap = this.#policy.heap;
|
|
2545
|
+
let i = heap.length;
|
|
2546
|
+
heap.push(entry);
|
|
1120
2547
|
while (i > 0) {
|
|
1121
2548
|
const parent = i - 1 >> 1;
|
|
1122
|
-
|
|
2549
|
+
const above = heap[parent];
|
|
2550
|
+
if (above.filed <= entry.filed)
|
|
1123
2551
|
break;
|
|
1124
|
-
|
|
2552
|
+
heap[i] = above;
|
|
1125
2553
|
i = parent;
|
|
1126
2554
|
}
|
|
2555
|
+
heap[i] = entry;
|
|
1127
2556
|
}
|
|
1128
2557
|
#heapPop() {
|
|
1129
|
-
const heap = this.#heap;
|
|
2558
|
+
const heap = this.#policy.heap;
|
|
1130
2559
|
const top = heap[0];
|
|
1131
2560
|
const last = heap.pop();
|
|
1132
2561
|
if (top === undefined || heap.length === 0)
|
|
1133
2562
|
return top;
|
|
1134
|
-
|
|
1135
|
-
for (
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
if (
|
|
1140
|
-
|
|
1141
|
-
if (
|
|
1142
|
-
smallest = right;
|
|
1143
|
-
if (smallest === i)
|
|
2563
|
+
let i = 0;
|
|
2564
|
+
for (;; ) {
|
|
2565
|
+
let child = 2 * i + 1;
|
|
2566
|
+
if (child >= heap.length)
|
|
2567
|
+
break;
|
|
2568
|
+
if (child + 1 < heap.length && heap[child + 1].filed < heap[child].filed)
|
|
2569
|
+
child++;
|
|
2570
|
+
if (heap[child].filed >= last.filed)
|
|
1144
2571
|
break;
|
|
1145
|
-
|
|
1146
|
-
i =
|
|
2572
|
+
heap[i] = heap[child];
|
|
2573
|
+
i = child;
|
|
1147
2574
|
}
|
|
2575
|
+
heap[i] = last;
|
|
1148
2576
|
return top;
|
|
1149
2577
|
}
|
|
1150
2578
|
first() {
|
|
@@ -1176,19 +2604,35 @@ class Collection extends Map {
|
|
|
1176
2604
|
}
|
|
1177
2605
|
return;
|
|
1178
2606
|
}
|
|
2607
|
+
findLast(predicate) {
|
|
2608
|
+
const keys = this.keyArray();
|
|
2609
|
+
const values = this.array();
|
|
2610
|
+
for (let i = values.length - 1;i >= 0; i--)
|
|
2611
|
+
if (predicate(values[i], keys[i], this))
|
|
2612
|
+
return values[i];
|
|
2613
|
+
return;
|
|
2614
|
+
}
|
|
2615
|
+
findLastKey(predicate) {
|
|
2616
|
+
const keys = this.keyArray();
|
|
2617
|
+
const values = this.array();
|
|
2618
|
+
for (let i = values.length - 1;i >= 0; i--)
|
|
2619
|
+
if (predicate(values[i], keys[i], this))
|
|
2620
|
+
return keys[i];
|
|
2621
|
+
return;
|
|
2622
|
+
}
|
|
1179
2623
|
filter(predicate) {
|
|
1180
|
-
const result =
|
|
1181
|
-
|
|
2624
|
+
const result = this.#derived();
|
|
2625
|
+
this.forEach((value, key) => {
|
|
1182
2626
|
if (predicate(value, key, this))
|
|
1183
2627
|
result.set(key, value);
|
|
1184
|
-
}
|
|
2628
|
+
});
|
|
1185
2629
|
return result;
|
|
1186
2630
|
}
|
|
1187
2631
|
map(transform) {
|
|
1188
2632
|
const result = [];
|
|
1189
|
-
|
|
2633
|
+
this.forEach((value, key) => {
|
|
1190
2634
|
result.push(transform(value, key, this));
|
|
1191
|
-
}
|
|
2635
|
+
});
|
|
1192
2636
|
return result;
|
|
1193
2637
|
}
|
|
1194
2638
|
some(predicate) {
|
|
@@ -1206,9 +2650,9 @@ class Collection extends Map {
|
|
|
1206
2650
|
return true;
|
|
1207
2651
|
}
|
|
1208
2652
|
each(callback) {
|
|
1209
|
-
|
|
2653
|
+
this.forEach((value, key) => {
|
|
1210
2654
|
callback(value, key, this);
|
|
1211
|
-
}
|
|
2655
|
+
});
|
|
1212
2656
|
return this;
|
|
1213
2657
|
}
|
|
1214
2658
|
array() {
|
|
@@ -1221,9 +2665,10 @@ class Collection extends Map {
|
|
|
1221
2665
|
return [...this.entries()];
|
|
1222
2666
|
}
|
|
1223
2667
|
clone() {
|
|
1224
|
-
const copy =
|
|
1225
|
-
|
|
2668
|
+
const copy = this.#derived();
|
|
2669
|
+
this.forEach((value, key) => {
|
|
1226
2670
|
copy.set(key, value);
|
|
2671
|
+
});
|
|
1227
2672
|
return copy;
|
|
1228
2673
|
}
|
|
1229
2674
|
hasAll(...keys) {
|
|
@@ -1276,7 +2721,7 @@ class Collection extends Map {
|
|
|
1276
2721
|
return result;
|
|
1277
2722
|
}
|
|
1278
2723
|
intersection(other) {
|
|
1279
|
-
const result =
|
|
2724
|
+
const result = this.#derived();
|
|
1280
2725
|
for (const [key, value] of this) {
|
|
1281
2726
|
if (other.has(key))
|
|
1282
2727
|
result.set(key, value);
|
|
@@ -1284,7 +2729,7 @@ class Collection extends Map {
|
|
|
1284
2729
|
return result;
|
|
1285
2730
|
}
|
|
1286
2731
|
difference(other) {
|
|
1287
|
-
const result =
|
|
2732
|
+
const result = this.#derived();
|
|
1288
2733
|
for (const [key, value] of this) {
|
|
1289
2734
|
if (!other.has(key))
|
|
1290
2735
|
result.set(key, value);
|
|
@@ -1292,8 +2737,8 @@ class Collection extends Map {
|
|
|
1292
2737
|
return result;
|
|
1293
2738
|
}
|
|
1294
2739
|
partition(predicate) {
|
|
1295
|
-
const pass =
|
|
1296
|
-
const fail =
|
|
2740
|
+
const pass = this.#derived();
|
|
2741
|
+
const fail = this.#derived();
|
|
1297
2742
|
for (const [key, value] of this) {
|
|
1298
2743
|
if (predicate(value, key, this))
|
|
1299
2744
|
pass.set(key, value);
|
|
@@ -1302,6 +2747,81 @@ class Collection extends Map {
|
|
|
1302
2747
|
}
|
|
1303
2748
|
return [pass, fail];
|
|
1304
2749
|
}
|
|
2750
|
+
symmetricDifference(other) {
|
|
2751
|
+
const result = this.#derived();
|
|
2752
|
+
for (const [key, value] of this)
|
|
2753
|
+
if (!other.has(key))
|
|
2754
|
+
result.set(key, value);
|
|
2755
|
+
for (const [key, value] of other)
|
|
2756
|
+
if (!this.has(key))
|
|
2757
|
+
result.set(key, value);
|
|
2758
|
+
return result;
|
|
2759
|
+
}
|
|
2760
|
+
concat(...collections) {
|
|
2761
|
+
const result = this.clone();
|
|
2762
|
+
for (const collection of collections)
|
|
2763
|
+
for (const [key, value] of collection)
|
|
2764
|
+
result.set(key, value);
|
|
2765
|
+
return result;
|
|
2766
|
+
}
|
|
2767
|
+
merge(other, whenInSelf, whenInOther, whenInBoth) {
|
|
2768
|
+
const result = this.#derived();
|
|
2769
|
+
const decide = (key, kept) => {
|
|
2770
|
+
if (kept.keep)
|
|
2771
|
+
result.set(key, kept.value);
|
|
2772
|
+
};
|
|
2773
|
+
for (const [key, value] of this) {
|
|
2774
|
+
decide(key, other.has(key) ? whenInBoth(value, peekOf(other, key), key) : whenInSelf(value, key));
|
|
2775
|
+
}
|
|
2776
|
+
for (const [key, value] of other)
|
|
2777
|
+
if (!this.has(key))
|
|
2778
|
+
decide(key, whenInOther(value, key));
|
|
2779
|
+
return result;
|
|
2780
|
+
}
|
|
2781
|
+
equals(other) {
|
|
2782
|
+
if (!other)
|
|
2783
|
+
return false;
|
|
2784
|
+
if (other === this)
|
|
2785
|
+
return true;
|
|
2786
|
+
if (this.size !== other.size)
|
|
2787
|
+
return false;
|
|
2788
|
+
for (const [key, value] of this) {
|
|
2789
|
+
if (!other.has(key))
|
|
2790
|
+
return false;
|
|
2791
|
+
if (value !== peekOf(other, key))
|
|
2792
|
+
return false;
|
|
2793
|
+
}
|
|
2794
|
+
return true;
|
|
2795
|
+
}
|
|
2796
|
+
mapValues(transform) {
|
|
2797
|
+
const result = this.#derived();
|
|
2798
|
+
for (const [key, value] of this)
|
|
2799
|
+
result.set(key, transform(value, key, this));
|
|
2800
|
+
return result;
|
|
2801
|
+
}
|
|
2802
|
+
toReversed() {
|
|
2803
|
+
const result = this.#derived();
|
|
2804
|
+
const entries = [...this];
|
|
2805
|
+
for (let i = entries.length - 1;i >= 0; i--)
|
|
2806
|
+
result.set(entries[i][0], entries[i][1]);
|
|
2807
|
+
return result;
|
|
2808
|
+
}
|
|
2809
|
+
toSorted(comparator) {
|
|
2810
|
+
return this.sorted(comparator);
|
|
2811
|
+
}
|
|
2812
|
+
static groupBy(items, keySelector) {
|
|
2813
|
+
const groups = new Collection;
|
|
2814
|
+
let index = 0;
|
|
2815
|
+
for (const item of items)
|
|
2816
|
+
groups.ensure(keySelector(item, index++), () => []).push(item);
|
|
2817
|
+
return groups;
|
|
2818
|
+
}
|
|
2819
|
+
static combineEntries(entries, combine) {
|
|
2820
|
+
const result = new Collection;
|
|
2821
|
+
for (const [key, value] of entries)
|
|
2822
|
+
result.set(key, result.has(key) ? combine(result.get(key), value, key) : value);
|
|
2823
|
+
return result;
|
|
2824
|
+
}
|
|
1305
2825
|
tap(fn) {
|
|
1306
2826
|
fn(this);
|
|
1307
2827
|
return this;
|
|
@@ -1320,6 +2840,13 @@ class Collection extends Map {
|
|
|
1320
2840
|
acc = fn(acc, value, key, this);
|
|
1321
2841
|
return acc;
|
|
1322
2842
|
}
|
|
2843
|
+
reduceRight(fn, initialValue) {
|
|
2844
|
+
const entries = [...this];
|
|
2845
|
+
let acc = initialValue;
|
|
2846
|
+
for (let i = entries.length - 1;i >= 0; i--)
|
|
2847
|
+
acc = fn(acc, entries[i][1], entries[i][0], this);
|
|
2848
|
+
return acc;
|
|
2849
|
+
}
|
|
1323
2850
|
sorted(comparator) {
|
|
1324
2851
|
const decorated = [...this.entries()].map((entry, index) => ({
|
|
1325
2852
|
entry,
|
|
@@ -1330,32 +2857,52 @@ class Collection extends Map {
|
|
|
1330
2857
|
const comparison = comparator(x.entry[1], y.entry[1], x.entry[0], y.entry[0]);
|
|
1331
2858
|
return comparison !== 0 ? comparison : x.index - y.index;
|
|
1332
2859
|
});
|
|
1333
|
-
const result =
|
|
2860
|
+
const result = this.#derived();
|
|
1334
2861
|
for (const { entry } of decorated)
|
|
1335
2862
|
result.set(entry[0], entry[1]);
|
|
1336
2863
|
return result;
|
|
1337
2864
|
}
|
|
1338
|
-
random() {
|
|
1339
|
-
|
|
1340
|
-
|
|
2865
|
+
random(amount) {
|
|
2866
|
+
if (amount !== undefined)
|
|
2867
|
+
return sample([...this.values()], amount);
|
|
2868
|
+
const size = this.size;
|
|
2869
|
+
if (size === 0)
|
|
1341
2870
|
return;
|
|
1342
|
-
|
|
2871
|
+
let index = Math.floor(Math.random() * size);
|
|
2872
|
+
for (const value of this.values())
|
|
2873
|
+
if (index-- === 0)
|
|
2874
|
+
return value;
|
|
2875
|
+
return;
|
|
1343
2876
|
}
|
|
1344
|
-
randomKey() {
|
|
1345
|
-
|
|
1346
|
-
|
|
2877
|
+
randomKey(amount) {
|
|
2878
|
+
if (amount !== undefined)
|
|
2879
|
+
return sample([...this.keys()], amount);
|
|
2880
|
+
const size = this.size;
|
|
2881
|
+
if (size === 0)
|
|
1347
2882
|
return;
|
|
1348
|
-
|
|
2883
|
+
let index = Math.floor(Math.random() * size);
|
|
2884
|
+
for (const key of this.keys())
|
|
2885
|
+
if (index-- === 0)
|
|
2886
|
+
return key;
|
|
2887
|
+
return;
|
|
1349
2888
|
}
|
|
1350
2889
|
at(index) {
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
2890
|
+
let remaining = index < 0 ? this.size + index : index;
|
|
2891
|
+
if (remaining < 0)
|
|
2892
|
+
return;
|
|
2893
|
+
for (const value of this.values())
|
|
2894
|
+
if (remaining-- === 0)
|
|
2895
|
+
return value;
|
|
2896
|
+
return;
|
|
1354
2897
|
}
|
|
1355
2898
|
keyAt(index) {
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
2899
|
+
let remaining = index < 0 ? this.size + index : index;
|
|
2900
|
+
if (remaining < 0)
|
|
2901
|
+
return;
|
|
2902
|
+
for (const key of this.keys())
|
|
2903
|
+
if (remaining-- === 0)
|
|
2904
|
+
return key;
|
|
2905
|
+
return;
|
|
1359
2906
|
}
|
|
1360
2907
|
toJSON() {
|
|
1361
2908
|
return [...this.entries()];
|
|
@@ -1469,7 +3016,7 @@ class ResourceManager extends Manager {
|
|
|
1469
3016
|
// packages/rest/package.json
|
|
1470
3017
|
var package_default = {
|
|
1471
3018
|
name: "@lunibee/rest",
|
|
1472
|
-
version: "0.
|
|
3019
|
+
version: "0.3.0",
|
|
1473
3020
|
type: "module",
|
|
1474
3021
|
module: "./src/index.ts",
|
|
1475
3022
|
types: "./src/index.ts",
|
|
@@ -1550,7 +3097,7 @@ function kindFromStatus(status) {
|
|
|
1550
3097
|
return "client";
|
|
1551
3098
|
}
|
|
1552
3099
|
function redactPath(path) {
|
|
1553
|
-
return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]
|
|
3100
|
+
return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/i, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/i, "$1:token");
|
|
1554
3101
|
}
|
|
1555
3102
|
var HINTS = {
|
|
1556
3103
|
50001: "The bot cannot see this resource: check that it is in the guild and has View Channel there.",
|
|
@@ -1609,19 +3156,23 @@ async function abortable(promise, signal, path) {
|
|
|
1609
3156
|
}
|
|
1610
3157
|
|
|
1611
3158
|
// packages/rest/src/route.ts
|
|
3159
|
+
import { createHash } from "crypto";
|
|
1612
3160
|
function normalizeRoutePath(path) {
|
|
1613
3161
|
const queryIndex = path.indexOf("?");
|
|
1614
3162
|
const routePath = queryIndex === -1 ? path : path.slice(0, queryIndex);
|
|
1615
|
-
return routePath.replace(/\/\d+(?=\/|$)/g, "/:id");
|
|
3163
|
+
return redactPath(routePath).replace(/\/\d+(?=\/|$)/g, "/:id");
|
|
1616
3164
|
}
|
|
1617
3165
|
function majorParameter(path) {
|
|
1618
|
-
const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))
|
|
3166
|
+
const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/i.exec(path);
|
|
1619
3167
|
if (!match)
|
|
1620
3168
|
return "@none";
|
|
1621
|
-
if (match[1] === "webhooks" && match[3] !== undefined)
|
|
1622
|
-
return `${match[2]}:${match[3]}`;
|
|
3169
|
+
if (match[1].toLowerCase() === "webhooks" && match[3] !== undefined)
|
|
3170
|
+
return `${match[2]}:${tokenDigest(match[3])}`;
|
|
1623
3171
|
return match[2];
|
|
1624
3172
|
}
|
|
3173
|
+
function tokenDigest(token) {
|
|
3174
|
+
return createHash("sha256").update(token).digest("hex").slice(0, 16);
|
|
3175
|
+
}
|
|
1625
3176
|
function scopeBucket(hashOrRoute, major) {
|
|
1626
3177
|
return `${hashOrRoute}|${major}`;
|
|
1627
3178
|
}
|
|
@@ -1863,6 +3414,9 @@ var Routes = {
|
|
|
1863
3414
|
user: () => "/users/@me",
|
|
1864
3415
|
userById: (userId) => `/users/${snowflake(userId, "User ID")}`,
|
|
1865
3416
|
guild: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}`,
|
|
3417
|
+
currentUserGuild: (guildId) => `/users/@me/guilds/${snowflake(guildId, "Guild ID")}`,
|
|
3418
|
+
sticker: (stickerId) => `/stickers/${snowflake(stickerId, "Sticker ID")}`,
|
|
3419
|
+
messageReactionUser: (channelId, messageId, emoji, userId) => `${Routes.messageReactions(channelId, messageId, emoji)}/${snowflake(userId, "User ID")}`,
|
|
1866
3420
|
guildPreview: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/preview`,
|
|
1867
3421
|
guildActiveThreads: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/threads/active`,
|
|
1868
3422
|
guildWebhooks: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/webhooks`,
|
|
@@ -1879,11 +3433,10 @@ var Routes = {
|
|
|
1879
3433
|
message: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/${snowflake(messageId, "Message ID")}`,
|
|
1880
3434
|
crosspostMessage: (channelId, messageId) => `${Routes.message(channelId, messageId)}/crosspost`,
|
|
1881
3435
|
messageReactions: (channelId, messageId, emoji) => `${Routes.message(channelId, messageId)}/reactions/${encodeURIComponent(emoji)}`,
|
|
3436
|
+
messageReactionMe: (channelId, messageId, emoji) => `${Routes.messageReactions(channelId, messageId, emoji)}/@me`,
|
|
1882
3437
|
messageReactionsAll: (channelId, messageId) => `${Routes.message(channelId, messageId)}/reactions`,
|
|
1883
3438
|
channelMessagesPins: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/pins`,
|
|
1884
3439
|
channelMessagesPin: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/pins/${snowflake(messageId, "Message ID")}`,
|
|
1885
|
-
channelPins: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/pins`,
|
|
1886
|
-
channelPin: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/pins/${snowflake(messageId, "Message ID")}`,
|
|
1887
3440
|
messageThread: (channelId, messageId) => `${Routes.message(channelId, messageId)}/threads`,
|
|
1888
3441
|
channelBulkDelete: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/bulk-delete`,
|
|
1889
3442
|
channelWebhooks: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/webhooks`,
|
|
@@ -1898,6 +3451,10 @@ var Routes = {
|
|
|
1898
3451
|
interactionOriginalResponse: (applicationId, token) => `/webhooks/${snowflake(applicationId, "Application ID")}/${encodeURIComponent(token)}/messages/@original`,
|
|
1899
3452
|
channelPublicArchivedThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/threads/archived/public`,
|
|
1900
3453
|
channelPrivateArchivedThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/threads/archived/private`,
|
|
3454
|
+
channelJoinedPrivateArchivedThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/users/@me/threads/archived/private`,
|
|
3455
|
+
threadMember: (threadId, userId) => `/channels/${snowflake(threadId, "Thread ID")}/thread-members/${userOrMe(userId)}`,
|
|
3456
|
+
channelTyping: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/typing`,
|
|
3457
|
+
channelThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/threads`,
|
|
1901
3458
|
threadMembers: (threadId) => `/channels/${snowflake(threadId, "Thread ID")}/thread-members`,
|
|
1902
3459
|
guildScheduledEvents: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/scheduled-events`,
|
|
1903
3460
|
guildScheduledEvent: (guildId, eventId) => `/guilds/${snowflake(guildId, "Guild ID")}/scheduled-events/${snowflake(eventId, "Event ID")}`,
|
|
@@ -1910,6 +3467,13 @@ var Routes = {
|
|
|
1910
3467
|
gatewayBot: () => "/gateway/bot",
|
|
1911
3468
|
guildAuditLog: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/audit-logs`,
|
|
1912
3469
|
guildMembers: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/members`,
|
|
3470
|
+
guildMembersSearch: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/members/search`,
|
|
3471
|
+
guildMemberMe: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/members/@me`,
|
|
3472
|
+
guildBulkBan: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/bulk-ban`,
|
|
3473
|
+
guildVoiceState: (guildId, userId) => `/guilds/${snowflake(guildId, "Guild ID")}/voice-states/${userOrMe(userId)}`,
|
|
3474
|
+
guildIntegration: (guildId, integrationId) => `/guilds/${snowflake(guildId, "Guild ID")}/integrations/${snowflake(integrationId, "Integration ID")}`,
|
|
3475
|
+
userGuilds: () => "/users/@me/guilds",
|
|
3476
|
+
stickerPacks: (packId) => packId ? `/sticker-packs/${snowflake(packId, "Sticker pack ID")}` : "/sticker-packs",
|
|
1913
3477
|
guildWelcomeScreen: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/welcome-screen`,
|
|
1914
3478
|
guildOnboarding: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/onboarding`,
|
|
1915
3479
|
guildPrune: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/prune`,
|
|
@@ -1930,6 +3494,9 @@ var Routes = {
|
|
|
1930
3494
|
consumeEntitlement: (applicationId, entitlementId) => `/applications/${snowflake(applicationId, "Application ID")}/entitlements/${snowflake(entitlementId, "Entitlement ID")}/consume`,
|
|
1931
3495
|
skuSubscription: (skuId, subscriptionId) => subscriptionId ? `/skus/${snowflake(skuId, "SKU ID")}/subscriptions/${snowflake(subscriptionId, "Subscription ID")}` : `/skus/${snowflake(skuId, "SKU ID")}/subscriptions`
|
|
1932
3496
|
};
|
|
3497
|
+
function userOrMe(value) {
|
|
3498
|
+
return value === "@me" ? value : snowflake(value, "User ID");
|
|
3499
|
+
}
|
|
1933
3500
|
function integer(value, field) {
|
|
1934
3501
|
if (!Number.isInteger(value) || value < 0)
|
|
1935
3502
|
throw new TypeError(`${field} must be a non-negative integer.`);
|
|
@@ -1945,6 +3512,22 @@ function snowflake(value, field) {
|
|
|
1945
3512
|
var LIBRARY_VERSION = package_default.version;
|
|
1946
3513
|
var LIBRARY_URL = "https://github.com/Ekretos/lunibee";
|
|
1947
3514
|
var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${LIBRARY_VERSION})`;
|
|
3515
|
+
function assertSafePath(path) {
|
|
3516
|
+
const end = path.search(/[?#]/);
|
|
3517
|
+
const pathname = end === -1 ? path : path.slice(0, end);
|
|
3518
|
+
if (pathname.includes("\\"))
|
|
3519
|
+
throw new TypeError("REST paths must not contain backslashes.");
|
|
3520
|
+
for (const segment of pathname.split("/")) {
|
|
3521
|
+
let decoded;
|
|
3522
|
+
try {
|
|
3523
|
+
decoded = decodeURIComponent(segment);
|
|
3524
|
+
} catch {
|
|
3525
|
+
throw new TypeError("REST path has malformed percent-encoding.");
|
|
3526
|
+
}
|
|
3527
|
+
if (decoded === "." || decoded === "..")
|
|
3528
|
+
throw new TypeError("REST paths must not contain '.' or '..' segments.");
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
1948
3531
|
var REQUEST_DATA_KEYS = new Set([
|
|
1949
3532
|
"body",
|
|
1950
3533
|
"files",
|
|
@@ -2005,7 +3588,7 @@ class REST {
|
|
|
2005
3588
|
timeout: options.timeout
|
|
2006
3589
|
});
|
|
2007
3590
|
const store = options.store ?? new MemoryRateLimitStore;
|
|
2008
|
-
this.#concurrentBuckets = (options.concurrentBuckets ??
|
|
3591
|
+
this.#concurrentBuckets = (options.concurrentBuckets ?? true) && typeof store.reserve === "function";
|
|
2009
3592
|
this.#limiter = new RateLimiter(store, {
|
|
2010
3593
|
concurrent: this.#concurrentBuckets
|
|
2011
3594
|
});
|
|
@@ -2029,6 +3612,7 @@ class REST {
|
|
|
2029
3612
|
throw new TypeError("REST method is required.");
|
|
2030
3613
|
if (!path.startsWith("/"))
|
|
2031
3614
|
throw new TypeError("REST paths must start with '/'.");
|
|
3615
|
+
assertSafePath(path);
|
|
2032
3616
|
const route = createRouteKey(method, path);
|
|
2033
3617
|
const files = options.files;
|
|
2034
3618
|
if (files && files.length > 0 && !(body instanceof FormData))
|
|
@@ -2116,13 +3700,19 @@ class REST {
|
|
|
2116
3700
|
#headers(body, options) {
|
|
2117
3701
|
const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
|
|
2118
3702
|
const headers = { ...options.headers };
|
|
3703
|
+
const set = (name, value) => {
|
|
3704
|
+
for (const key of Object.keys(headers))
|
|
3705
|
+
if (key.toLowerCase() === name.toLowerCase())
|
|
3706
|
+
delete headers[key];
|
|
3707
|
+
headers[name] = value;
|
|
3708
|
+
};
|
|
2119
3709
|
if (options.auth !== false && this.#token)
|
|
2120
|
-
|
|
2121
|
-
|
|
3710
|
+
set("Authorization", `Bot ${this.#token}`);
|
|
3711
|
+
set("User-Agent", USER_AGENT);
|
|
2122
3712
|
if (options.reason !== undefined)
|
|
2123
|
-
|
|
3713
|
+
set("X-Audit-Log-Reason", encodeURIComponent(options.reason));
|
|
2124
3714
|
if (!isFormData)
|
|
2125
|
-
|
|
3715
|
+
set("Content-Type", "application/json");
|
|
2126
3716
|
return headers;
|
|
2127
3717
|
}
|
|
2128
3718
|
#encodeBody(body) {
|
|
@@ -2189,8 +3779,11 @@ class BaseStructure {
|
|
|
2189
3779
|
toString() {
|
|
2190
3780
|
return this.id;
|
|
2191
3781
|
}
|
|
3782
|
+
get createdTimestamp() {
|
|
3783
|
+
return Number((BigInt(this.id) >> 22n) + 1420070400000n);
|
|
3784
|
+
}
|
|
2192
3785
|
get createdAt() {
|
|
2193
|
-
return new Date(
|
|
3786
|
+
return new Date(this.createdTimestamp);
|
|
2194
3787
|
}
|
|
2195
3788
|
}
|
|
2196
3789
|
var CDN_BASE = "https://cdn.discordapp.com";
|
|
@@ -2198,7 +3791,7 @@ function cdnURL(path, hash, options = {}) {
|
|
|
2198
3791
|
const isAnimated = hash.startsWith("a_") && !options.forceStatic;
|
|
2199
3792
|
const ext = options.extension ?? (isAnimated ? "gif" : "png");
|
|
2200
3793
|
const size = options.size ? `?size=${options.size}` : "";
|
|
2201
|
-
return `${CDN_BASE}${path}/${hash}.${ext}${size}`;
|
|
3794
|
+
return `${CDN_BASE}${path}/${encodeURIComponent(hash)}.${ext}${size}`;
|
|
2202
3795
|
}
|
|
2203
3796
|
|
|
2204
3797
|
class User extends BaseStructure {
|
|
@@ -2272,9 +3865,6 @@ class Channel extends BaseStructure {
|
|
|
2272
3865
|
throw new Error("This channel is not attached to a client.");
|
|
2273
3866
|
return this.#context.sendMessage(this.id, options);
|
|
2274
3867
|
}
|
|
2275
|
-
sendMessage(options) {
|
|
2276
|
-
return this.send(options);
|
|
2277
|
-
}
|
|
2278
3868
|
edit(options) {
|
|
2279
3869
|
if (!this.#context?.editChannel)
|
|
2280
3870
|
throw new Error("This channel is not attached to a client.");
|
|
@@ -2304,6 +3894,17 @@ class Channel extends BaseStructure {
|
|
|
2304
3894
|
update(options) {
|
|
2305
3895
|
return this.edit(options);
|
|
2306
3896
|
}
|
|
3897
|
+
get kind() {
|
|
3898
|
+
return channelKindOf(this.type);
|
|
3899
|
+
}
|
|
3900
|
+
is(...kinds) {
|
|
3901
|
+
return kinds.includes(this.kind);
|
|
3902
|
+
}
|
|
3903
|
+
as(...kinds) {
|
|
3904
|
+
if (!this.is(...kinds))
|
|
3905
|
+
throw new TypeError(`Channel ${this.id} is a ${this.kind} channel, not ${kinds.join(" or ")}.`);
|
|
3906
|
+
return this;
|
|
3907
|
+
}
|
|
2307
3908
|
isThread() {
|
|
2308
3909
|
return this.type === 10 || this.type === 11 || this.type === 12;
|
|
2309
3910
|
}
|
|
@@ -2355,6 +3956,7 @@ class Guild extends BaseStructure {
|
|
|
2355
3956
|
safetyAlertsChannelId;
|
|
2356
3957
|
maxPresences;
|
|
2357
3958
|
maxVideoChannelUsers;
|
|
3959
|
+
premiumProgressBarEnabled;
|
|
2358
3960
|
constructor(data) {
|
|
2359
3961
|
super(data.id);
|
|
2360
3962
|
if (!data.name)
|
|
@@ -2392,6 +3994,7 @@ class Guild extends BaseStructure {
|
|
|
2392
3994
|
this.safetyAlertsChannelId = data.safety_alerts_channel_id ?? null;
|
|
2393
3995
|
this.maxPresences = data.max_presences ?? null;
|
|
2394
3996
|
this.maxVideoChannelUsers = data.max_video_channel_users;
|
|
3997
|
+
this.premiumProgressBarEnabled = data.premium_progress_bar_enabled ?? false;
|
|
2395
3998
|
}
|
|
2396
3999
|
iconURL(options = {}) {
|
|
2397
4000
|
if (!this.icon)
|
|
@@ -2488,10 +4091,10 @@ class GuildMember {
|
|
|
2488
4091
|
get permissions() {
|
|
2489
4092
|
if (this.#suppliedPermissions)
|
|
2490
4093
|
return this.#suppliedPermissions;
|
|
2491
|
-
return new PermissionsBitField(this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds) ?? 0n);
|
|
4094
|
+
return new PermissionsBitField(this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, undefined, this.timedOutUntil) ?? 0n);
|
|
2492
4095
|
}
|
|
2493
4096
|
permissionsIn(channelId) {
|
|
2494
|
-
const computed = this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, channelId);
|
|
4097
|
+
const computed = this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, channelId, this.timedOutUntil);
|
|
2495
4098
|
return computed ? new PermissionsBitField(computed) : null;
|
|
2496
4099
|
}
|
|
2497
4100
|
#action(name) {
|
|
@@ -2554,6 +4157,7 @@ class Role extends BaseStructure {
|
|
|
2554
4157
|
position;
|
|
2555
4158
|
unicodeEmoji;
|
|
2556
4159
|
iconHash;
|
|
4160
|
+
colors;
|
|
2557
4161
|
tags;
|
|
2558
4162
|
constructor(data) {
|
|
2559
4163
|
super(data.id);
|
|
@@ -2567,6 +4171,11 @@ class Role extends BaseStructure {
|
|
|
2567
4171
|
this.mentionable = data.mentionable ?? false;
|
|
2568
4172
|
this.position = data.position ?? 0;
|
|
2569
4173
|
this.unicodeEmoji = data.unicode_emoji ?? null;
|
|
4174
|
+
this.colors = data.colors ? {
|
|
4175
|
+
primary: data.colors.primary_color,
|
|
4176
|
+
secondary: data.colors.secondary_color,
|
|
4177
|
+
tertiary: data.colors.tertiary_color
|
|
4178
|
+
} : null;
|
|
2570
4179
|
this.iconHash = data.icon ?? null;
|
|
2571
4180
|
this.tags = data.tags ?? null;
|
|
2572
4181
|
}
|
|
@@ -3030,6 +4639,14 @@ class Interaction {
|
|
|
3030
4639
|
this.type = data.type;
|
|
3031
4640
|
this.data = data;
|
|
3032
4641
|
}
|
|
4642
|
+
get entitlements() {
|
|
4643
|
+
const entitlements = this.data.entitlements;
|
|
4644
|
+
return Array.isArray(entitlements) ? entitlements : [];
|
|
4645
|
+
}
|
|
4646
|
+
hasEntitlement(skuId) {
|
|
4647
|
+
const now = Date.now();
|
|
4648
|
+
return this.entitlements.some((entitlement) => entitlement.sku_id === skuId && !entitlement.deleted && (!entitlement.ends_at || Date.parse(entitlement.ends_at) > now));
|
|
4649
|
+
}
|
|
3033
4650
|
#commandType() {
|
|
3034
4651
|
if (this.type !== InteractionEnum.ApplicationCommand)
|
|
3035
4652
|
return 0;
|
|
@@ -3324,22 +4941,133 @@ function findFocused(options) {
|
|
|
3324
4941
|
return found;
|
|
3325
4942
|
}
|
|
3326
4943
|
}
|
|
3327
|
-
return;
|
|
3328
|
-
}
|
|
3329
|
-
function createInteraction(client, data) {
|
|
3330
|
-
switch (data.type) {
|
|
3331
|
-
case InteractionEnum.ApplicationCommand: {
|
|
3332
|
-
const commandType = data.data?.type;
|
|
3333
|
-
return commandType === COMMAND_USER || commandType === COMMAND_MESSAGE ? new ContextMenuCommandInteraction(client, data) : new CommandInteraction(client, data);
|
|
3334
|
-
}
|
|
3335
|
-
case InteractionEnum.ApplicationCommandAutocomplete:
|
|
3336
|
-
return new AutocompleteInteraction(client, data);
|
|
3337
|
-
case InteractionEnum.MessageComponent:
|
|
3338
|
-
return new ComponentInteraction(client, data);
|
|
3339
|
-
case InteractionEnum.ModalSubmit:
|
|
3340
|
-
return new ModalSubmitInteraction(client, data);
|
|
3341
|
-
default:
|
|
3342
|
-
return new Interaction(client, data);
|
|
4944
|
+
return;
|
|
4945
|
+
}
|
|
4946
|
+
function createInteraction(client, data) {
|
|
4947
|
+
switch (data.type) {
|
|
4948
|
+
case InteractionEnum.ApplicationCommand: {
|
|
4949
|
+
const commandType = data.data?.type;
|
|
4950
|
+
return commandType === COMMAND_USER || commandType === COMMAND_MESSAGE ? new ContextMenuCommandInteraction(client, data) : new CommandInteraction(client, data);
|
|
4951
|
+
}
|
|
4952
|
+
case InteractionEnum.ApplicationCommandAutocomplete:
|
|
4953
|
+
return new AutocompleteInteraction(client, data);
|
|
4954
|
+
case InteractionEnum.MessageComponent:
|
|
4955
|
+
return new ComponentInteraction(client, data);
|
|
4956
|
+
case InteractionEnum.ModalSubmit:
|
|
4957
|
+
return new ModalSubmitInteraction(client, data);
|
|
4958
|
+
default:
|
|
4959
|
+
return new Interaction(client, data);
|
|
4960
|
+
}
|
|
4961
|
+
}
|
|
4962
|
+
// packages/structures/src/audit-log.ts
|
|
4963
|
+
function int(value) {
|
|
4964
|
+
return Number(value ?? 0);
|
|
4965
|
+
}
|
|
4966
|
+
function parseInfo(type, options) {
|
|
4967
|
+
if (!options)
|
|
4968
|
+
return;
|
|
4969
|
+
switch (type) {
|
|
4970
|
+
case 13:
|
|
4971
|
+
case 14:
|
|
4972
|
+
case 15:
|
|
4973
|
+
return {
|
|
4974
|
+
id: options.id ?? "",
|
|
4975
|
+
type: int(options.type),
|
|
4976
|
+
roleName: options.role_name
|
|
4977
|
+
};
|
|
4978
|
+
case 21:
|
|
4979
|
+
return {
|
|
4980
|
+
deleteMemberDays: int(options.delete_member_days),
|
|
4981
|
+
membersRemoved: int(options.members_removed)
|
|
4982
|
+
};
|
|
4983
|
+
case 26:
|
|
4984
|
+
case 72:
|
|
4985
|
+
return {
|
|
4986
|
+
channelId: options.channel_id ?? "",
|
|
4987
|
+
count: int(options.count)
|
|
4988
|
+
};
|
|
4989
|
+
case 27:
|
|
4990
|
+
case 73:
|
|
4991
|
+
return { count: int(options.count) };
|
|
4992
|
+
case 74:
|
|
4993
|
+
case 75:
|
|
4994
|
+
return {
|
|
4995
|
+
channelId: options.channel_id ?? "",
|
|
4996
|
+
messageId: options.message_id ?? ""
|
|
4997
|
+
};
|
|
4998
|
+
case 83:
|
|
4999
|
+
case 84:
|
|
5000
|
+
case 85:
|
|
5001
|
+
return { channelId: options.channel_id ?? "" };
|
|
5002
|
+
case 121:
|
|
5003
|
+
return { applicationId: options.app_id ?? "" };
|
|
5004
|
+
case 143:
|
|
5005
|
+
case 144:
|
|
5006
|
+
case 145:
|
|
5007
|
+
return {
|
|
5008
|
+
ruleName: options.auto_moderation_rule_name ?? "",
|
|
5009
|
+
ruleTriggerType: int(options.auto_moderation_rule_trigger_type),
|
|
5010
|
+
channelId: options.channel_id
|
|
5011
|
+
};
|
|
5012
|
+
default:
|
|
5013
|
+
return;
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
|
|
5017
|
+
class AuditLogEntry extends BaseStructure {
|
|
5018
|
+
targetId;
|
|
5019
|
+
userId;
|
|
5020
|
+
actionType;
|
|
5021
|
+
changes;
|
|
5022
|
+
options;
|
|
5023
|
+
info;
|
|
5024
|
+
reason;
|
|
5025
|
+
constructor(data) {
|
|
5026
|
+
super(data.id);
|
|
5027
|
+
this.targetId = data.target_id;
|
|
5028
|
+
this.userId = data.user_id;
|
|
5029
|
+
this.actionType = data.action_type;
|
|
5030
|
+
this.info = parseInfo(data.action_type, data.options);
|
|
5031
|
+
this.changes = data.changes ?? [];
|
|
5032
|
+
this.options = data.options ?? null;
|
|
5033
|
+
this.reason = data.reason ?? null;
|
|
5034
|
+
}
|
|
5035
|
+
is(type) {
|
|
5036
|
+
return this.actionType === type;
|
|
5037
|
+
}
|
|
5038
|
+
change(key) {
|
|
5039
|
+
const found = this.changes.find((change) => change.key === key);
|
|
5040
|
+
return found && { old: found.old_value, new: found.new_value };
|
|
5041
|
+
}
|
|
5042
|
+
}
|
|
5043
|
+
|
|
5044
|
+
class AuditLog {
|
|
5045
|
+
entries;
|
|
5046
|
+
constructor(data) {
|
|
5047
|
+
this.entries = new Map;
|
|
5048
|
+
for (const entryData of data.audit_log_entries) {
|
|
5049
|
+
this.entries.set(entryData.id, new AuditLogEntry(entryData));
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
filter(query) {
|
|
5053
|
+
const types = query.type === undefined ? undefined : Array.isArray(query.type) ? query.type : [query.type];
|
|
5054
|
+
const since = query.since === undefined ? undefined : new Date(query.since).getTime();
|
|
5055
|
+
const matches = [];
|
|
5056
|
+
for (const entry of this.entries.values()) {
|
|
5057
|
+
if (types && !types.includes(entry.actionType))
|
|
5058
|
+
continue;
|
|
5059
|
+
if (query.targetId !== undefined && entry.targetId !== query.targetId)
|
|
5060
|
+
continue;
|
|
5061
|
+
if (query.userId !== undefined && entry.userId !== query.userId)
|
|
5062
|
+
continue;
|
|
5063
|
+
if (since !== undefined && entry.createdAt.getTime() < since)
|
|
5064
|
+
continue;
|
|
5065
|
+
matches.push(entry);
|
|
5066
|
+
}
|
|
5067
|
+
return matches;
|
|
5068
|
+
}
|
|
5069
|
+
find(query) {
|
|
5070
|
+
return this.filter(query)[0];
|
|
3343
5071
|
}
|
|
3344
5072
|
}
|
|
3345
5073
|
|
|
@@ -3530,6 +5258,13 @@ class Message extends BaseStructure {
|
|
|
3530
5258
|
}
|
|
3531
5259
|
|
|
3532
5260
|
// packages/managers/src/message.ts
|
|
5261
|
+
function toAttachments(files) {
|
|
5262
|
+
return files.map((file) => ({
|
|
5263
|
+
name: file.name,
|
|
5264
|
+
data: typeof file.data === "string" ? new TextEncoder().encode(file.data) : file.data,
|
|
5265
|
+
contentType: file.contentType
|
|
5266
|
+
}));
|
|
5267
|
+
}
|
|
3533
5268
|
function toRequest(options, allowedMentions) {
|
|
3534
5269
|
const { files, ...body } = options;
|
|
3535
5270
|
if (allowedMentions !== undefined && body.allowed_mentions === undefined)
|
|
@@ -3538,11 +5273,7 @@ function toRequest(options, allowedMentions) {
|
|
|
3538
5273
|
return body;
|
|
3539
5274
|
return {
|
|
3540
5275
|
body,
|
|
3541
|
-
files: files
|
|
3542
|
-
name: file.name,
|
|
3543
|
-
data: typeof file.data === "string" ? new TextEncoder().encode(file.data) : file.data,
|
|
3544
|
-
contentType: file.contentType
|
|
3545
|
-
}))
|
|
5276
|
+
files: toAttachments(files)
|
|
3546
5277
|
};
|
|
3547
5278
|
}
|
|
3548
5279
|
|
|
@@ -3616,6 +5347,70 @@ class ThreadManager {
|
|
|
3616
5347
|
});
|
|
3617
5348
|
return createChannel(data, this.#context);
|
|
3618
5349
|
}
|
|
5350
|
+
async create(options) {
|
|
5351
|
+
const data = await this.#rest.post(Routes.channelThreads(this.#channelId), {
|
|
5352
|
+
name: options.name,
|
|
5353
|
+
type: options.type ?? 12,
|
|
5354
|
+
auto_archive_duration: options.autoArchiveDuration,
|
|
5355
|
+
rate_limit_per_user: options.rateLimitPerUser,
|
|
5356
|
+
invitable: options.invitable
|
|
5357
|
+
}, { reason: options.reason });
|
|
5358
|
+
return createChannel(data, this.#context);
|
|
5359
|
+
}
|
|
5360
|
+
async createForumPost(options) {
|
|
5361
|
+
const { message, appliedTags, reason, ...thread } = options;
|
|
5362
|
+
const { files, ...content } = message;
|
|
5363
|
+
const data = await this.#rest.post(Routes.channelThreads(this.#channelId), {
|
|
5364
|
+
name: thread.name,
|
|
5365
|
+
auto_archive_duration: thread.autoArchiveDuration,
|
|
5366
|
+
rate_limit_per_user: thread.rateLimitPerUser,
|
|
5367
|
+
applied_tags: appliedTags,
|
|
5368
|
+
message: content
|
|
5369
|
+
}, { files: files?.length ? toAttachments(files) : undefined, reason });
|
|
5370
|
+
return createChannel(data, this.#context);
|
|
5371
|
+
}
|
|
5372
|
+
async fetchArchived(scope, options = {}) {
|
|
5373
|
+
const route = scope === "public" ? Routes.channelPublicArchivedThreads(this.#channelId) : scope === "private" ? Routes.channelPrivateArchivedThreads(this.#channelId) : Routes.channelJoinedPrivateArchivedThreads(this.#channelId);
|
|
5374
|
+
const params = new URLSearchParams;
|
|
5375
|
+
if (options.before)
|
|
5376
|
+
params.set("before", options.before);
|
|
5377
|
+
if (options.limit !== undefined)
|
|
5378
|
+
params.set("limit", String(Math.min(100, Math.max(1, options.limit))));
|
|
5379
|
+
const query = params.toString();
|
|
5380
|
+
const page = await this.#rest.get(`${route}${query ? `?${query}` : ""}`);
|
|
5381
|
+
return {
|
|
5382
|
+
threads: page.threads.map((thread) => createChannel(thread, this.#context)),
|
|
5383
|
+
members: page.members,
|
|
5384
|
+
hasMore: page.has_more
|
|
5385
|
+
};
|
|
5386
|
+
}
|
|
5387
|
+
async join(threadId) {
|
|
5388
|
+
await this.#rest.put(Routes.threadMember(threadId, "@me"));
|
|
5389
|
+
}
|
|
5390
|
+
async leave(threadId) {
|
|
5391
|
+
await this.#rest.delete(Routes.threadMember(threadId, "@me"));
|
|
5392
|
+
}
|
|
5393
|
+
async addMember(threadId, userId) {
|
|
5394
|
+
await this.#rest.put(Routes.threadMember(threadId, userId));
|
|
5395
|
+
}
|
|
5396
|
+
async removeMember(threadId, userId) {
|
|
5397
|
+
await this.#rest.delete(Routes.threadMember(threadId, userId));
|
|
5398
|
+
}
|
|
5399
|
+
async fetchMember(threadId, userId, query = {}) {
|
|
5400
|
+
const suffix = query.withMember ? "?with_member=true" : "";
|
|
5401
|
+
return this.#rest.get(`${Routes.threadMember(threadId, userId)}${suffix}`);
|
|
5402
|
+
}
|
|
5403
|
+
async fetchMembers(threadId, options = {}) {
|
|
5404
|
+
const params = new URLSearchParams;
|
|
5405
|
+
if (options.withMember)
|
|
5406
|
+
params.set("with_member", "true");
|
|
5407
|
+
if (options.after)
|
|
5408
|
+
params.set("after", options.after);
|
|
5409
|
+
if (options.limit !== undefined)
|
|
5410
|
+
params.set("limit", String(Math.min(100, Math.max(1, options.limit))));
|
|
5411
|
+
const query = params.toString();
|
|
5412
|
+
return this.#rest.get(`${Routes.threadMembers(threadId)}${query ? `?${query}` : ""}`);
|
|
5413
|
+
}
|
|
3619
5414
|
}
|
|
3620
5415
|
|
|
3621
5416
|
// packages/managers/src/user.ts
|
|
@@ -3633,8 +5428,21 @@ class UserManager extends ResourceManager {
|
|
|
3633
5428
|
const data = await this.#rest.patch("/users/@me", options);
|
|
3634
5429
|
return this.upsert(new User(data));
|
|
3635
5430
|
}
|
|
5431
|
+
async fetchGuilds(options = {}) {
|
|
5432
|
+
const params = new URLSearchParams;
|
|
5433
|
+
if (options.limit !== undefined)
|
|
5434
|
+
params.set("limit", String(Math.min(200, Math.max(1, options.limit))));
|
|
5435
|
+
if (options.before)
|
|
5436
|
+
params.set("before", options.before);
|
|
5437
|
+
if (options.after)
|
|
5438
|
+
params.set("after", options.after);
|
|
5439
|
+
if (options.withCounts)
|
|
5440
|
+
params.set("with_counts", "true");
|
|
5441
|
+
const query = params.toString();
|
|
5442
|
+
return this.#rest.get(`${Routes.userGuilds()}${query ? `?${query}` : ""}`);
|
|
5443
|
+
}
|
|
3636
5444
|
async leaveGuild(guildId) {
|
|
3637
|
-
await this.#rest.delete(
|
|
5445
|
+
await this.#rest.delete(Routes.currentUserGuild(guildId));
|
|
3638
5446
|
}
|
|
3639
5447
|
async createDM(userId) {
|
|
3640
5448
|
return this.#rest.post("/users/@me/channels", {
|
|
@@ -3672,9 +5480,6 @@ class EmojiManager extends Manager {
|
|
|
3672
5480
|
});
|
|
3673
5481
|
this.delete(emojiId);
|
|
3674
5482
|
}
|
|
3675
|
-
deleteEmoji(emojiId) {
|
|
3676
|
-
return this.remove(emojiId);
|
|
3677
|
-
}
|
|
3678
5483
|
upsert(data) {
|
|
3679
5484
|
const key = data.id != null ? data.id : `unicode:${data.name ?? ""}`;
|
|
3680
5485
|
return this.#merge(key, new Emoji(data));
|
|
@@ -3855,6 +5660,39 @@ class MonetizationManager extends Manager {
|
|
|
3855
5660
|
}
|
|
3856
5661
|
}
|
|
3857
5662
|
|
|
5663
|
+
class ApplicationEmojiManager extends Manager {
|
|
5664
|
+
#rest;
|
|
5665
|
+
applicationId;
|
|
5666
|
+
constructor(rest, applicationId) {
|
|
5667
|
+
super();
|
|
5668
|
+
this.#rest = rest;
|
|
5669
|
+
this.applicationId = applicationId;
|
|
5670
|
+
}
|
|
5671
|
+
#store(emoji) {
|
|
5672
|
+
if (emoji.id)
|
|
5673
|
+
this.set(emoji.id, emoji);
|
|
5674
|
+
return emoji;
|
|
5675
|
+
}
|
|
5676
|
+
async fetchAll() {
|
|
5677
|
+
const { items } = await this.#rest.get(Routes.applicationEmoji(this.applicationId));
|
|
5678
|
+
this.clear();
|
|
5679
|
+
return items.map((emoji) => this.#store(emoji));
|
|
5680
|
+
}
|
|
5681
|
+
async fetch(emojiId) {
|
|
5682
|
+
return this.#store(await this.#rest.get(Routes.applicationEmoji(this.applicationId, emojiId)));
|
|
5683
|
+
}
|
|
5684
|
+
async create(options) {
|
|
5685
|
+
return this.#store(await this.#rest.post(Routes.applicationEmoji(this.applicationId), options));
|
|
5686
|
+
}
|
|
5687
|
+
async edit(emojiId, options) {
|
|
5688
|
+
return this.#store(await this.#rest.patch(Routes.applicationEmoji(this.applicationId, emojiId), options));
|
|
5689
|
+
}
|
|
5690
|
+
async remove(emojiId) {
|
|
5691
|
+
await this.#rest.delete(Routes.applicationEmoji(this.applicationId, emojiId));
|
|
5692
|
+
this.delete(emojiId);
|
|
5693
|
+
}
|
|
5694
|
+
}
|
|
5695
|
+
|
|
3858
5696
|
// packages/managers/src/member.ts
|
|
3859
5697
|
class GuildMemberManager extends ResourceManager {
|
|
3860
5698
|
#rest;
|
|
@@ -3868,6 +5706,27 @@ class GuildMemberManager extends ResourceManager {
|
|
|
3868
5706
|
this.#rest = rest;
|
|
3869
5707
|
this.#context = context;
|
|
3870
5708
|
}
|
|
5709
|
+
async search(query, limit = 1) {
|
|
5710
|
+
if (!query.trim())
|
|
5711
|
+
throw new TypeError("A search query is required.");
|
|
5712
|
+
const params = new URLSearchParams({
|
|
5713
|
+
query,
|
|
5714
|
+
limit: String(Math.min(1000, Math.max(1, limit)))
|
|
5715
|
+
});
|
|
5716
|
+
const found = await this.#rest.get(`${Routes.guildMembersSearch(this.guildId)}?${params}`);
|
|
5717
|
+
return found.map((data) => {
|
|
5718
|
+
const member = new GuildMember({ ...data, guild_id: this.guildId }, this.#context());
|
|
5719
|
+
this.set(member.user.id, member);
|
|
5720
|
+
return member;
|
|
5721
|
+
});
|
|
5722
|
+
}
|
|
5723
|
+
async editMe(options) {
|
|
5724
|
+
const [payload, reason] = splitReason(options);
|
|
5725
|
+
const data = await this.#rest.patch(Routes.guildMemberMe(this.guildId), payload, { reason });
|
|
5726
|
+
const member = new GuildMember({ ...data, guild_id: this.guildId }, this.#context());
|
|
5727
|
+
this.set(member.user.id, member);
|
|
5728
|
+
return member;
|
|
5729
|
+
}
|
|
3871
5730
|
async kick(userId, reason) {
|
|
3872
5731
|
await this.#rest.delete(Routes.guildMember(this.guildId, userId), {
|
|
3873
5732
|
reason
|
|
@@ -3883,10 +5742,10 @@ class GuildMemberManager extends ResourceManager {
|
|
|
3883
5742
|
reason
|
|
3884
5743
|
});
|
|
3885
5744
|
}
|
|
3886
|
-
async edit(userId, options
|
|
5745
|
+
async edit(userId, options) {
|
|
3887
5746
|
const [payload, optionsReason] = splitReason(options);
|
|
3888
5747
|
const data = await this.#rest.patch(Routes.guildMember(this.guildId, userId), payload, {
|
|
3889
|
-
reason: optionsReason
|
|
5748
|
+
reason: optionsReason
|
|
3890
5749
|
});
|
|
3891
5750
|
const member = new GuildMember({ ...data, guild_id: this.guildId }, this.#context());
|
|
3892
5751
|
this.set(member.user.id, member);
|
|
@@ -3900,7 +5759,10 @@ class GuildMemberManager extends ResourceManager {
|
|
|
3900
5759
|
}
|
|
3901
5760
|
async timeout(userId, milliseconds, reason) {
|
|
3902
5761
|
const timeoutDate = milliseconds === null ? null : new Date(Date.now() + milliseconds).toISOString();
|
|
3903
|
-
return this.edit(userId, {
|
|
5762
|
+
return this.edit(userId, {
|
|
5763
|
+
communication_disabled_until: timeoutDate,
|
|
5764
|
+
reason
|
|
5765
|
+
});
|
|
3904
5766
|
}
|
|
3905
5767
|
}
|
|
3906
5768
|
|
|
@@ -3923,20 +5785,15 @@ class RoleManager extends ResourceManager {
|
|
|
3923
5785
|
}
|
|
3924
5786
|
async create(options) {
|
|
3925
5787
|
const { reason, ...payload } = options;
|
|
3926
|
-
const data = await this.#rest.post(Routes.guildRoles(this.guildId), {
|
|
3927
|
-
|
|
3928
|
-
permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
|
|
3929
|
-
}, { reason });
|
|
3930
|
-
const role = new Role(data);
|
|
3931
|
-
this.set(role.id, role);
|
|
3932
|
-
return role;
|
|
5788
|
+
const data = await this.#rest.post(Routes.guildRoles(this.guildId), rolePayload(payload), { reason });
|
|
5789
|
+
return this.#store(data);
|
|
3933
5790
|
}
|
|
3934
5791
|
async edit(roleId, options) {
|
|
3935
5792
|
const { reason, ...payload } = options;
|
|
3936
|
-
const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), {
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
5793
|
+
const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), rolePayload(payload), { reason });
|
|
5794
|
+
return this.#store(data);
|
|
5795
|
+
}
|
|
5796
|
+
#store(data) {
|
|
3940
5797
|
const role = new Role(data);
|
|
3941
5798
|
this.set(role.id, role);
|
|
3942
5799
|
return role;
|
|
@@ -3955,9 +5812,19 @@ class RoleManager extends ResourceManager {
|
|
|
3955
5812
|
return role;
|
|
3956
5813
|
});
|
|
3957
5814
|
}
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
}
|
|
5815
|
+
}
|
|
5816
|
+
function rolePayload(options) {
|
|
5817
|
+
const { permissions, colors, unicodeEmoji, ...rest } = options;
|
|
5818
|
+
return {
|
|
5819
|
+
...rest,
|
|
5820
|
+
permissions: permissions !== undefined ? String(permissions) : undefined,
|
|
5821
|
+
colors: colors && {
|
|
5822
|
+
primary_color: colors.primary,
|
|
5823
|
+
secondary_color: colors.secondary ?? null,
|
|
5824
|
+
tertiary_color: colors.tertiary ?? null
|
|
5825
|
+
},
|
|
5826
|
+
unicode_emoji: unicodeEmoji
|
|
5827
|
+
};
|
|
3961
5828
|
}
|
|
3962
5829
|
|
|
3963
5830
|
// packages/managers/src/guild-resources.ts
|
|
@@ -3997,6 +5864,18 @@ class GuildBanManager extends Manager {
|
|
|
3997
5864
|
async create(userId, options = {}) {
|
|
3998
5865
|
await this.#rest.put(Routes.guildBan(this.guildId, userId), { delete_message_seconds: options.deleteMessageSeconds }, { reason: options.reason });
|
|
3999
5866
|
}
|
|
5867
|
+
async bulk(userIds, options = {}) {
|
|
5868
|
+
if (userIds.length < 1 || userIds.length > 200)
|
|
5869
|
+
throw new RangeError("Bulk ban takes 1 to 200 user IDs.");
|
|
5870
|
+
const result = await this.#rest.post(Routes.guildBulkBan(this.guildId), {
|
|
5871
|
+
user_ids: userIds,
|
|
5872
|
+
delete_message_seconds: options.deleteMessageSeconds
|
|
5873
|
+
}, { reason: options.reason });
|
|
5874
|
+
return {
|
|
5875
|
+
banned: result.banned_users ?? [],
|
|
5876
|
+
failed: result.failed_users ?? []
|
|
5877
|
+
};
|
|
5878
|
+
}
|
|
4000
5879
|
async remove(userId, reason) {
|
|
4001
5880
|
await this.#rest.delete(Routes.guildBan(this.guildId, userId), {
|
|
4002
5881
|
reason
|
|
@@ -4028,13 +5907,13 @@ class GuildScheduledEventManager extends Manager {
|
|
|
4028
5907
|
}));
|
|
4029
5908
|
return events.map((event) => this.#store(event));
|
|
4030
5909
|
}
|
|
4031
|
-
async create(options
|
|
5910
|
+
async create(options) {
|
|
4032
5911
|
const [payload, optionsReason] = splitReason(options);
|
|
4033
|
-
return this.#store(await this.#rest.post(Routes.guildScheduledEvents(this.guildId), payload, { reason: optionsReason
|
|
5912
|
+
return this.#store(await this.#rest.post(Routes.guildScheduledEvents(this.guildId), payload, { reason: optionsReason }));
|
|
4034
5913
|
}
|
|
4035
|
-
async edit(eventId, options
|
|
5914
|
+
async edit(eventId, options) {
|
|
4036
5915
|
const [payload, optionsReason] = splitReason(options);
|
|
4037
|
-
return this.#store(await this.#rest.patch(Routes.guildScheduledEvent(this.guildId, eventId), payload, { reason: optionsReason
|
|
5916
|
+
return this.#store(await this.#rest.patch(Routes.guildScheduledEvent(this.guildId, eventId), payload, { reason: optionsReason }));
|
|
4038
5917
|
}
|
|
4039
5918
|
async remove(eventId, reason) {
|
|
4040
5919
|
await this.#rest.delete(Routes.guildScheduledEvent(this.guildId, eventId), { reason });
|
|
@@ -4061,20 +5940,20 @@ class StageInstanceManager extends Manager {
|
|
|
4061
5940
|
this.set(stage.channel_id, stage);
|
|
4062
5941
|
return stage;
|
|
4063
5942
|
}
|
|
4064
|
-
async create(channelId, options
|
|
5943
|
+
async create(channelId, options) {
|
|
4065
5944
|
return this.#store(await this.#rest.post(Routes.stageInstances(), {
|
|
4066
5945
|
channel_id: channelId,
|
|
4067
5946
|
topic: options.topic,
|
|
4068
5947
|
privacy_level: options.privacyLevel,
|
|
4069
5948
|
send_start_notification: options.sendStartNotification,
|
|
4070
5949
|
guild_scheduled_event_id: options.guildScheduledEventId
|
|
4071
|
-
}, { reason: options.reason
|
|
5950
|
+
}, { reason: options.reason }));
|
|
4072
5951
|
}
|
|
4073
5952
|
async fetch(channelId) {
|
|
4074
5953
|
return this.#store(await this.#rest.get(Routes.stageInstanceByChannel(channelId)));
|
|
4075
5954
|
}
|
|
4076
|
-
async edit(channelId, options
|
|
4077
|
-
return this.#store(await this.#rest.patch(Routes.stageInstanceByChannel(channelId), { topic: options.topic, privacy_level: options.privacyLevel }, { reason: options.reason
|
|
5955
|
+
async edit(channelId, options) {
|
|
5956
|
+
return this.#store(await this.#rest.patch(Routes.stageInstanceByChannel(channelId), { topic: options.topic, privacy_level: options.privacyLevel }, { reason: options.reason }));
|
|
4078
5957
|
}
|
|
4079
5958
|
async remove(channelId, reason) {
|
|
4080
5959
|
await this.#rest.delete(Routes.stageInstanceByChannel(channelId), {
|
|
@@ -4104,14 +5983,19 @@ class PermissionOverwriteManager {
|
|
|
4104
5983
|
const touched = (changes.allow ?? 0n) | (changes.deny ?? 0n) | (changes.inherit ?? 0n);
|
|
4105
5984
|
const allow = BigInt(existing?.allow ?? 0) & ~touched | (changes.allow ?? 0n);
|
|
4106
5985
|
const deny = BigInt(existing?.deny ?? 0) & ~touched | (changes.deny ?? 0n);
|
|
4107
|
-
await this.edit(overwriteId, {
|
|
5986
|
+
await this.edit(overwriteId, {
|
|
5987
|
+
type,
|
|
5988
|
+
allow,
|
|
5989
|
+
deny,
|
|
5990
|
+
reason: options.reason
|
|
5991
|
+
});
|
|
4108
5992
|
}
|
|
4109
|
-
async edit(overwriteId, options
|
|
5993
|
+
async edit(overwriteId, options) {
|
|
4110
5994
|
await this.#rest.put(Routes.channelPermission(this.channelId, overwriteId), {
|
|
4111
5995
|
type: options.type,
|
|
4112
5996
|
allow: BigInt(options.allow ?? 0).toString(),
|
|
4113
5997
|
deny: BigInt(options.deny ?? 0).toString()
|
|
4114
|
-
}, { reason: options.reason
|
|
5998
|
+
}, { reason: options.reason });
|
|
4115
5999
|
}
|
|
4116
6000
|
async remove(overwriteId, reason) {
|
|
4117
6001
|
await this.#rest.delete(Routes.channelPermission(this.channelId, overwriteId), { reason });
|
|
@@ -4135,6 +6019,7 @@ class GuildManager extends ResourceManager {
|
|
|
4135
6019
|
#soundboard = new Map;
|
|
4136
6020
|
#voiceStates = new Map;
|
|
4137
6021
|
#autoModerationRules = new Map;
|
|
6022
|
+
#presences = new Map;
|
|
4138
6023
|
#invites = new Map;
|
|
4139
6024
|
#context;
|
|
4140
6025
|
attachContext(context) {
|
|
@@ -4195,6 +6080,9 @@ class GuildManager extends ResourceManager {
|
|
|
4195
6080
|
voiceStates(guildId) {
|
|
4196
6081
|
return this.#perGuild(this.#voiceStates, guildId, () => new Manager);
|
|
4197
6082
|
}
|
|
6083
|
+
presences(guildId) {
|
|
6084
|
+
return this.#perGuild(this.#presences, guildId, () => new Manager);
|
|
6085
|
+
}
|
|
4198
6086
|
autoModerationRules(guildId) {
|
|
4199
6087
|
return this.#perGuild(this.#autoModerationRules, guildId, () => new Manager);
|
|
4200
6088
|
}
|
|
@@ -4220,6 +6108,7 @@ class GuildManager extends ResourceManager {
|
|
|
4220
6108
|
this.#stickers.delete(id);
|
|
4221
6109
|
this.#soundboard.delete(id);
|
|
4222
6110
|
this.#voiceStates.delete(id);
|
|
6111
|
+
this.#presences.delete(id);
|
|
4223
6112
|
this.#autoModerationRules.delete(id);
|
|
4224
6113
|
this.#invites.delete(id);
|
|
4225
6114
|
return super.delete(id);
|
|
@@ -4236,12 +6125,35 @@ class GuildManager extends ResourceManager {
|
|
|
4236
6125
|
async remove(id) {
|
|
4237
6126
|
await this.#rest.delete(Routes.guild(id));
|
|
4238
6127
|
}
|
|
4239
|
-
deleteGuild(id) {
|
|
4240
|
-
return this.remove(id);
|
|
4241
|
-
}
|
|
4242
6128
|
async fetchPreview(id) {
|
|
4243
6129
|
return this.#rest.get(Routes.guildPreview(id));
|
|
4244
6130
|
}
|
|
6131
|
+
async fetchWelcomeScreen(id) {
|
|
6132
|
+
return this.#rest.get(Routes.guildWelcomeScreen(id));
|
|
6133
|
+
}
|
|
6134
|
+
async editWelcomeScreen(id, options) {
|
|
6135
|
+
const { reason, welcomeChannels, ...rest } = options;
|
|
6136
|
+
return this.#rest.patch(Routes.guildWelcomeScreen(id), { ...rest, welcome_channels: welcomeChannels }, { reason });
|
|
6137
|
+
}
|
|
6138
|
+
async fetchOnboarding(id) {
|
|
6139
|
+
return this.#rest.get(Routes.guildOnboarding(id));
|
|
6140
|
+
}
|
|
6141
|
+
async editOnboarding(id, options) {
|
|
6142
|
+
const { reason, defaultChannelIds, ...rest } = options;
|
|
6143
|
+
return this.#rest.put(Routes.guildOnboarding(id), { ...rest, default_channel_ids: defaultChannelIds }, { reason });
|
|
6144
|
+
}
|
|
6145
|
+
async editVoiceState(id, userId, options) {
|
|
6146
|
+
await this.#rest.patch(Routes.guildVoiceState(id, userId), {
|
|
6147
|
+
channel_id: options.channelId,
|
|
6148
|
+
suppress: options.suppress,
|
|
6149
|
+
request_to_speak_timestamp: options.requestToSpeakTimestamp
|
|
6150
|
+
});
|
|
6151
|
+
}
|
|
6152
|
+
async removeIntegration(id, integrationId, reason) {
|
|
6153
|
+
await this.#rest.delete(Routes.guildIntegration(id, integrationId), {
|
|
6154
|
+
reason
|
|
6155
|
+
});
|
|
6156
|
+
}
|
|
4245
6157
|
async fetchActiveThreads(id) {
|
|
4246
6158
|
return this.#rest.get(Routes.guildActiveThreads(id));
|
|
4247
6159
|
}
|
|
@@ -4265,6 +6177,9 @@ class GuildManager extends ResourceManager {
|
|
|
4265
6177
|
params.set("limit", String(Math.min(100, Math.max(1, options.limit))));
|
|
4266
6178
|
return this.#rest.get(withQuery3(Routes.guildAuditLog(guildId), params));
|
|
4267
6179
|
}
|
|
6180
|
+
async fetchAuditLogEntries(guildId, options = {}) {
|
|
6181
|
+
return new AuditLog(await this.fetchAuditLog(guildId, options));
|
|
6182
|
+
}
|
|
4268
6183
|
async fetchMembers(guildId, options = {}) {
|
|
4269
6184
|
const params = new URLSearchParams;
|
|
4270
6185
|
if (options.limit !== undefined)
|
|
@@ -4445,9 +6360,6 @@ class ChannelManager extends Manager {
|
|
|
4445
6360
|
await this.#rest.delete(Routes.channel(channelId), { reason });
|
|
4446
6361
|
this.delete(channelId);
|
|
4447
6362
|
}
|
|
4448
|
-
deleteChannel(channelId) {
|
|
4449
|
-
return this.remove(channelId);
|
|
4450
|
-
}
|
|
4451
6363
|
delete(channelId) {
|
|
4452
6364
|
this.#messageManagers.delete(channelId);
|
|
4453
6365
|
return super.delete(channelId);
|
|
@@ -4455,9 +6367,6 @@ class ChannelManager extends Manager {
|
|
|
4455
6367
|
send(channelId, options) {
|
|
4456
6368
|
return this.messages(channelId).send(options);
|
|
4457
6369
|
}
|
|
4458
|
-
sendMessage(channelId, options) {
|
|
4459
|
-
return this.send(channelId, options);
|
|
4460
|
-
}
|
|
4461
6370
|
async fetchMessage(channelId, messageId, options = {}) {
|
|
4462
6371
|
return this.messages(channelId).fetch(messageId);
|
|
4463
6372
|
}
|
|
@@ -4526,7 +6435,7 @@ class ChannelManager extends Manager {
|
|
|
4526
6435
|
}
|
|
4527
6436
|
}
|
|
4528
6437
|
async addReaction(channelId, messageId, emoji) {
|
|
4529
|
-
await this.#rest.put(
|
|
6438
|
+
await this.#rest.put(Routes.messageReactionMe(channelId, messageId, emoji));
|
|
4530
6439
|
}
|
|
4531
6440
|
async fetchReactions(channelId, messageId, emoji, options = {}) {
|
|
4532
6441
|
const params = new URLSearchParams;
|
|
@@ -4539,10 +6448,10 @@ class ChannelManager extends Manager {
|
|
|
4539
6448
|
return data.map((user) => new User(user));
|
|
4540
6449
|
}
|
|
4541
6450
|
async removeOwnReaction(channelId, messageId, emoji) {
|
|
4542
|
-
await this.#rest.delete(
|
|
6451
|
+
await this.#rest.delete(Routes.messageReactionMe(channelId, messageId, emoji));
|
|
4543
6452
|
}
|
|
4544
6453
|
async removeReaction(channelId, messageId, emoji, userId) {
|
|
4545
|
-
await this.#rest.delete(
|
|
6454
|
+
await this.#rest.delete(Routes.messageReactionUser(channelId, messageId, emoji, userId));
|
|
4546
6455
|
}
|
|
4547
6456
|
async removeAllReactions(channelId, messageId) {
|
|
4548
6457
|
await this.#rest.delete(Routes.messageReactionsAll(channelId, messageId));
|
|
@@ -4551,6 +6460,46 @@ class ChannelManager extends Manager {
|
|
|
4551
6460
|
const data = await this.#rest.get(Routes.channelMessagesPins(channelId));
|
|
4552
6461
|
return data.items.map((item) => this.messages(channelId).upsert(item.message));
|
|
4553
6462
|
}
|
|
6463
|
+
async fetchPins(channelId, options = {}) {
|
|
6464
|
+
const params = new URLSearchParams;
|
|
6465
|
+
if (options.before)
|
|
6466
|
+
params.set("before", options.before);
|
|
6467
|
+
if (options.limit !== undefined)
|
|
6468
|
+
params.set("limit", String(Math.min(50, Math.max(1, options.limit))));
|
|
6469
|
+
const query = params.toString();
|
|
6470
|
+
const data = await this.#rest.get(`${Routes.channelMessagesPins(channelId)}${query ? `?${query}` : ""}`);
|
|
6471
|
+
return {
|
|
6472
|
+
messages: data.items.map((item) => this.messages(channelId).upsert(item.message)),
|
|
6473
|
+
hasMore: data.has_more
|
|
6474
|
+
};
|
|
6475
|
+
}
|
|
6476
|
+
async triggerTyping(channelId) {
|
|
6477
|
+
await this.#rest.post(Routes.channelTyping(channelId));
|
|
6478
|
+
}
|
|
6479
|
+
async createForumTag(channelId, tag, reason) {
|
|
6480
|
+
const tags = await this.#forumTags(channelId);
|
|
6481
|
+
return this.#saveForumTags(channelId, [...tags, tag], reason);
|
|
6482
|
+
}
|
|
6483
|
+
async editForumTag(channelId, tagId, changes, reason) {
|
|
6484
|
+
const tags = await this.#forumTags(channelId);
|
|
6485
|
+
if (!tags.some((tag) => tag.id === tagId))
|
|
6486
|
+
throw new Error(`Channel ${channelId} has no tag ${tagId}.`);
|
|
6487
|
+
return this.#saveForumTags(channelId, tags.map((tag) => tag.id === tagId ? { ...tag, ...changes } : tag), reason);
|
|
6488
|
+
}
|
|
6489
|
+
async removeForumTag(channelId, tagId, reason) {
|
|
6490
|
+
const tags = await this.#forumTags(channelId);
|
|
6491
|
+
if (!tags.some((tag) => tag.id === tagId))
|
|
6492
|
+
throw new Error(`Channel ${channelId} has no tag ${tagId}.`);
|
|
6493
|
+
return this.#saveForumTags(channelId, tags.filter((tag) => tag.id !== tagId), reason);
|
|
6494
|
+
}
|
|
6495
|
+
async#forumTags(channelId) {
|
|
6496
|
+
const channel = await this.#rest.get(Routes.channel(channelId));
|
|
6497
|
+
return channel.available_tags ?? [];
|
|
6498
|
+
}
|
|
6499
|
+
async#saveForumTags(channelId, tags, reason) {
|
|
6500
|
+
const updated = await this.#rest.patch(Routes.channel(channelId), { available_tags: tags }, { reason });
|
|
6501
|
+
return updated.available_tags ?? [];
|
|
6502
|
+
}
|
|
4554
6503
|
async pinMessage(channelId, messageId, reason) {
|
|
4555
6504
|
await this.#rest.put(Routes.channelMessagesPin(channelId, messageId), undefined, { reason });
|
|
4556
6505
|
}
|
|
@@ -4579,9 +6528,6 @@ class ChannelManager extends Manager {
|
|
|
4579
6528
|
hasMore: messages.length === limit
|
|
4580
6529
|
};
|
|
4581
6530
|
}
|
|
4582
|
-
bulkDelete(channelId, messageIds) {
|
|
4583
|
-
return this.bulkDeleteMessages(channelId, messageIds);
|
|
4584
|
-
}
|
|
4585
6531
|
clear() {
|
|
4586
6532
|
this.#messageManagers.clear();
|
|
4587
6533
|
super.clear();
|
|
@@ -4665,7 +6611,26 @@ class GatewaySession {
|
|
|
4665
6611
|
return resume ? { type: "resume", ...resume } : { type: "identify" };
|
|
4666
6612
|
}
|
|
4667
6613
|
connectURL(fallback) {
|
|
4668
|
-
|
|
6614
|
+
const resume = this.resumeInfo()?.resumeURL;
|
|
6615
|
+
return resume !== undefined && isTrustedGatewayURL(resume, fallback) ? resume : fallback;
|
|
6616
|
+
}
|
|
6617
|
+
}
|
|
6618
|
+
function isTrustedGatewayURL(url, fallback) {
|
|
6619
|
+
let parsed;
|
|
6620
|
+
try {
|
|
6621
|
+
parsed = new URL(url);
|
|
6622
|
+
} catch {
|
|
6623
|
+
return false;
|
|
6624
|
+
}
|
|
6625
|
+
if (parsed.protocol !== "wss:" || parsed.username || parsed.password)
|
|
6626
|
+
return false;
|
|
6627
|
+
const host = parsed.hostname.toLowerCase();
|
|
6628
|
+
if (host === "discord.gg" || host.endsWith(".discord.gg"))
|
|
6629
|
+
return true;
|
|
6630
|
+
try {
|
|
6631
|
+
return host === new URL(fallback).hostname.toLowerCase();
|
|
6632
|
+
} catch {
|
|
6633
|
+
return false;
|
|
4669
6634
|
}
|
|
4670
6635
|
}
|
|
4671
6636
|
|
|
@@ -4837,6 +6802,7 @@ class GatewayReconnect {
|
|
|
4837
6802
|
#options;
|
|
4838
6803
|
#random;
|
|
4839
6804
|
#attempt = 0;
|
|
6805
|
+
#recent = [];
|
|
4840
6806
|
#timer;
|
|
4841
6807
|
#promise;
|
|
4842
6808
|
#resolve;
|
|
@@ -4877,14 +6843,29 @@ class GatewayReconnect {
|
|
|
4877
6843
|
if (this.exhausted)
|
|
4878
6844
|
return { scheduled: false, reason: "exhausted" };
|
|
4879
6845
|
const attempt = this.#attempt;
|
|
4880
|
-
const
|
|
6846
|
+
const now = (this.#options.now ?? Date.now)();
|
|
6847
|
+
const window = this.#options.stormWindow ?? 60000;
|
|
6848
|
+
const limit = this.#options.stormLimit ?? 5;
|
|
6849
|
+
while (this.#recent.length && now - this.#recent[0] >= window)
|
|
6850
|
+
this.#recent.shift();
|
|
6851
|
+
const over = this.#recent.length - limit;
|
|
6852
|
+
this.#recent.push(now);
|
|
6853
|
+
let delay = Math.min(this.#options.maxDelay, this.#options.baseDelay * 2 ** this.#attempt++);
|
|
6854
|
+
const unstable = over >= 0;
|
|
6855
|
+
if (unstable)
|
|
6856
|
+
delay = Math.min(this.#options.maxDelay, Math.max(delay, this.#options.baseDelay * 2 ** (over + 1)));
|
|
4881
6857
|
const jitter = this.#random() * Math.max(1, delay * 0.25);
|
|
4882
6858
|
const delayMs = delay + jitter;
|
|
4883
6859
|
this.#timer = setTimeout(() => {
|
|
4884
6860
|
this.#timer = undefined;
|
|
4885
6861
|
run();
|
|
4886
6862
|
}, delayMs);
|
|
4887
|
-
return {
|
|
6863
|
+
return {
|
|
6864
|
+
scheduled: true,
|
|
6865
|
+
delayMs,
|
|
6866
|
+
attempt,
|
|
6867
|
+
...unstable ? { unstable: { reconnects: this.#recent.length } } : {}
|
|
6868
|
+
};
|
|
4888
6869
|
}
|
|
4889
6870
|
cancel() {
|
|
4890
6871
|
if (this.#timer)
|
|
@@ -4941,12 +6922,15 @@ class PlainTextDecoder {
|
|
|
4941
6922
|
|
|
4942
6923
|
class ZlibStreamDecoder {
|
|
4943
6924
|
#create;
|
|
6925
|
+
#maxFrameBytes;
|
|
4944
6926
|
#inflate;
|
|
4945
6927
|
#chunks = [];
|
|
6928
|
+
#size = 0;
|
|
4946
6929
|
#failure;
|
|
4947
6930
|
#pendingReject;
|
|
4948
|
-
constructor(create = () => createInflate()) {
|
|
6931
|
+
constructor(create = () => createInflate(), maxFrameBytes = 64 * 1024 * 1024) {
|
|
4949
6932
|
this.#create = create;
|
|
6933
|
+
this.#maxFrameBytes = maxFrameBytes;
|
|
4950
6934
|
}
|
|
4951
6935
|
push(data) {
|
|
4952
6936
|
if (typeof data === "string")
|
|
@@ -4965,6 +6949,7 @@ class ZlibStreamDecoder {
|
|
|
4965
6949
|
await this.#awaiting((settle) => inflate.flush(zlibConstants.Z_SYNC_FLUSH, () => settle()));
|
|
4966
6950
|
const parts = this.#chunks;
|
|
4967
6951
|
this.#chunks = [];
|
|
6952
|
+
this.#size = 0;
|
|
4968
6953
|
if (parts.length === 0)
|
|
4969
6954
|
return [];
|
|
4970
6955
|
const total = parts.reduce((size, part) => size + part.length, 0);
|
|
@@ -4980,6 +6965,7 @@ class ZlibStreamDecoder {
|
|
|
4980
6965
|
const inflate = this.#inflate;
|
|
4981
6966
|
this.#inflate = undefined;
|
|
4982
6967
|
this.#chunks = [];
|
|
6968
|
+
this.#size = 0;
|
|
4983
6969
|
this.#failure = undefined;
|
|
4984
6970
|
this.#pendingReject = undefined;
|
|
4985
6971
|
if (!inflate)
|
|
@@ -5007,7 +6993,17 @@ class ZlibStreamDecoder {
|
|
|
5007
6993
|
}
|
|
5008
6994
|
#open() {
|
|
5009
6995
|
const inflate = this.#create();
|
|
5010
|
-
inflate.on("data", (chunk) =>
|
|
6996
|
+
inflate.on("data", (chunk) => {
|
|
6997
|
+
if (this.#failure)
|
|
6998
|
+
return;
|
|
6999
|
+
this.#size += chunk.length;
|
|
7000
|
+
if (this.#size > this.#maxFrameBytes) {
|
|
7001
|
+
this.#chunks = [];
|
|
7002
|
+
inflate.emit("error", new Error(`Gateway frame inflated past ${this.#maxFrameBytes} bytes.`));
|
|
7003
|
+
return;
|
|
7004
|
+
}
|
|
7005
|
+
this.#chunks.push(chunk);
|
|
7006
|
+
});
|
|
5011
7007
|
inflate.on("error", (error) => {
|
|
5012
7008
|
this.#failure = error;
|
|
5013
7009
|
const reject = this.#pendingReject;
|
|
@@ -5250,9 +7246,9 @@ function classifyPayload(payload) {
|
|
|
5250
7246
|
}
|
|
5251
7247
|
function identifyPayload(options) {
|
|
5252
7248
|
const props = options.properties ?? {};
|
|
5253
|
-
const os = props.os ??
|
|
5254
|
-
const browser = props.browser ?? "
|
|
5255
|
-
const device = props.device ?? "
|
|
7249
|
+
const os = props.os ?? process.platform;
|
|
7250
|
+
const browser = props.browser ?? "Lunibee";
|
|
7251
|
+
const device = props.device ?? "Lunibee";
|
|
5256
7252
|
return {
|
|
5257
7253
|
op: GatewayOpcodes.Identify,
|
|
5258
7254
|
d: {
|
|
@@ -5294,17 +7290,40 @@ function resumePayload(token, resume) {
|
|
|
5294
7290
|
function heartbeatPayload(sequence) {
|
|
5295
7291
|
return { op: GatewayOpcodes.Heartbeat, d: sequence, s: null, t: null };
|
|
5296
7292
|
}
|
|
5297
|
-
// packages/ws/src/
|
|
5298
|
-
class
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
this
|
|
5303
|
-
|
|
7293
|
+
// packages/ws/src/dispatcher.ts
|
|
7294
|
+
class GatewayDispatcher {
|
|
7295
|
+
#listeners = new Map;
|
|
7296
|
+
#onFailure;
|
|
7297
|
+
constructor(onFailure) {
|
|
7298
|
+
this.#onFailure = onFailure;
|
|
7299
|
+
}
|
|
7300
|
+
on(event, listener) {
|
|
7301
|
+
let listeners = this.#listeners.get(event);
|
|
7302
|
+
if (!listeners)
|
|
7303
|
+
this.#listeners.set(event, listeners = new Set);
|
|
7304
|
+
listeners.add(listener);
|
|
7305
|
+
}
|
|
7306
|
+
off(event, listener) {
|
|
7307
|
+
this.#listeners.get(event)?.delete(listener);
|
|
7308
|
+
}
|
|
7309
|
+
emit(event, data) {
|
|
7310
|
+
for (const listener of this.#listeners.get(event) ?? []) {
|
|
7311
|
+
try {
|
|
7312
|
+
const result = listener(data);
|
|
7313
|
+
if (result && typeof result.then === "function")
|
|
7314
|
+
Promise.resolve(result).catch((error) => {
|
|
7315
|
+
if (event !== "error")
|
|
7316
|
+
this.#onFailure(error);
|
|
7317
|
+
});
|
|
7318
|
+
} catch (error) {
|
|
7319
|
+
if (event !== "error")
|
|
7320
|
+
this.#onFailure(error);
|
|
7321
|
+
}
|
|
7322
|
+
}
|
|
5304
7323
|
}
|
|
5305
7324
|
}
|
|
5306
7325
|
// packages/ws/src/send-budget.ts
|
|
5307
|
-
class
|
|
7326
|
+
class GatewaySendLimiter {
|
|
5308
7327
|
#timestamps = [];
|
|
5309
7328
|
#limit;
|
|
5310
7329
|
#windowMs;
|
|
@@ -5324,7 +7343,15 @@ class SendBudget {
|
|
|
5324
7343
|
this.#timestamps.push(now);
|
|
5325
7344
|
}
|
|
5326
7345
|
}
|
|
5327
|
-
|
|
7346
|
+
// packages/ws/src/state.ts
|
|
7347
|
+
class GatewayError extends Error {
|
|
7348
|
+
code;
|
|
7349
|
+
constructor(message, code, options) {
|
|
7350
|
+
super(message, options);
|
|
7351
|
+
this.name = "GatewayError";
|
|
7352
|
+
this.code = code;
|
|
7353
|
+
}
|
|
7354
|
+
}
|
|
5328
7355
|
// packages/ws/src/index.ts
|
|
5329
7356
|
var RESUMABLE_CLOSE_CODE = 4900;
|
|
5330
7357
|
var DEFAULT_GATEWAY_URL = "wss://gateway.discord.gg/?v=10&encoding=json";
|
|
@@ -5338,8 +7365,9 @@ class Gateway {
|
|
|
5338
7365
|
#heartbeat;
|
|
5339
7366
|
#closed = false;
|
|
5340
7367
|
#reconnect;
|
|
5341
|
-
#
|
|
5342
|
-
#sendBudget = new
|
|
7368
|
+
#events = new GatewayDispatcher((error) => this.#emitError(error));
|
|
7369
|
+
#sendBudget = new GatewaySendLimiter;
|
|
7370
|
+
#reconnects = 0;
|
|
5343
7371
|
ping = -1;
|
|
5344
7372
|
constructor(options) {
|
|
5345
7373
|
if (!options.token?.trim())
|
|
@@ -5357,9 +7385,9 @@ class Gateway {
|
|
|
5357
7385
|
heartbeatAckTimeout: 1e4,
|
|
5358
7386
|
zombieTimeout: 30000,
|
|
5359
7387
|
properties: {
|
|
5360
|
-
os:
|
|
5361
|
-
browser: "
|
|
5362
|
-
device: "
|
|
7388
|
+
os: process.platform,
|
|
7389
|
+
browser: "Lunibee",
|
|
7390
|
+
device: "Lunibee"
|
|
5363
7391
|
},
|
|
5364
7392
|
presence: {
|
|
5365
7393
|
status: "online",
|
|
@@ -5390,7 +7418,9 @@ class Gateway {
|
|
|
5390
7418
|
enabled: this.#options.reconnect,
|
|
5391
7419
|
maxAttempts: this.#options.maxReconnectAttempts,
|
|
5392
7420
|
baseDelay: this.#options.reconnectBaseDelay,
|
|
5393
|
-
maxDelay: this.#options.reconnectMaxDelay
|
|
7421
|
+
maxDelay: this.#options.reconnectMaxDelay,
|
|
7422
|
+
stormLimit: options.reconnectStormLimit,
|
|
7423
|
+
stormWindow: options.reconnectStormWindow
|
|
5394
7424
|
});
|
|
5395
7425
|
this.#heartbeat = new GatewayHeartbeat({
|
|
5396
7426
|
ackTimeout: this.#options.heartbeatAckTimeout,
|
|
@@ -5441,16 +7471,21 @@ class Gateway {
|
|
|
5441
7471
|
on(event, listener) {
|
|
5442
7472
|
if (!event || typeof listener !== "function")
|
|
5443
7473
|
throw new TypeError("Gateway event and listener are required.");
|
|
5444
|
-
|
|
5445
|
-
if (!listeners)
|
|
5446
|
-
this.#listeners.set(event, listeners = new Set);
|
|
5447
|
-
listeners.add(listener);
|
|
7474
|
+
this.#events.on(event, listener);
|
|
5448
7475
|
return this;
|
|
5449
7476
|
}
|
|
5450
7477
|
off(event, listener) {
|
|
5451
|
-
this.#
|
|
7478
|
+
this.#events.off(event, listener);
|
|
5452
7479
|
return this;
|
|
5453
7480
|
}
|
|
7481
|
+
health() {
|
|
7482
|
+
return {
|
|
7483
|
+
state: this.state,
|
|
7484
|
+
latency: this.#heartbeat.latency,
|
|
7485
|
+
silentFor: this.#heartbeat.silentFor,
|
|
7486
|
+
reconnects: this.#reconnects
|
|
7487
|
+
};
|
|
7488
|
+
}
|
|
5454
7489
|
send(payload) {
|
|
5455
7490
|
if (!payload || !Number.isInteger(payload.op))
|
|
5456
7491
|
throw new TypeError("Gateway payload must contain an integer opcode.");
|
|
@@ -5492,6 +7527,22 @@ class Gateway {
|
|
|
5492
7527
|
t: null
|
|
5493
7528
|
});
|
|
5494
7529
|
}
|
|
7530
|
+
sendVoiceState(guildId, channelId, options = {}) {
|
|
7531
|
+
if (!this.ownsGuild(guildId))
|
|
7532
|
+
return false;
|
|
7533
|
+
return this.setVoiceState({
|
|
7534
|
+
guild_id: guildId,
|
|
7535
|
+
channel_id: channelId,
|
|
7536
|
+
self_mute: options.selfMute ?? false,
|
|
7537
|
+
self_deaf: options.selfDeaf ?? false
|
|
7538
|
+
});
|
|
7539
|
+
}
|
|
7540
|
+
ownsGuild(guildId) {
|
|
7541
|
+
const count = this.#options.shardCount;
|
|
7542
|
+
if (count <= 1)
|
|
7543
|
+
return true;
|
|
7544
|
+
return Number((BigInt(guildId) >> 22n) % BigInt(count)) === this.#options.shardId;
|
|
7545
|
+
}
|
|
5495
7546
|
requestGuildMembers(data) {
|
|
5496
7547
|
return this.send({
|
|
5497
7548
|
op: GatewayOpcodes.RequestGuildMembers,
|
|
@@ -5629,7 +7680,16 @@ class Gateway {
|
|
|
5629
7680
|
if (this.#closed)
|
|
5630
7681
|
return;
|
|
5631
7682
|
const result = this.#reconnect.schedule(() => this.#open(this.#session.connectURL(DEFAULT_GATEWAY_URL)));
|
|
5632
|
-
if (result.scheduled
|
|
7683
|
+
if (result.scheduled) {
|
|
7684
|
+
this.#reconnects++;
|
|
7685
|
+
if (result.unstable)
|
|
7686
|
+
this.#emit("unstable", {
|
|
7687
|
+
reconnects: result.unstable.reconnects,
|
|
7688
|
+
delay: result.delayMs
|
|
7689
|
+
});
|
|
7690
|
+
return;
|
|
7691
|
+
}
|
|
7692
|
+
if (result.reason !== "exhausted")
|
|
5633
7693
|
return;
|
|
5634
7694
|
this.#reconnect.settle(new GatewayError("Gateway reconnect attempts exhausted."));
|
|
5635
7695
|
this.#setState("CONNECT" /* Connect */);
|
|
@@ -5650,19 +7710,7 @@ class Gateway {
|
|
|
5650
7710
|
this.#emit("error", error instanceof Error ? error : new GatewayError(String(error)));
|
|
5651
7711
|
}
|
|
5652
7712
|
#emit(event, data) {
|
|
5653
|
-
|
|
5654
|
-
try {
|
|
5655
|
-
const result = listener(data);
|
|
5656
|
-
if (result && typeof result.then === "function")
|
|
5657
|
-
Promise.resolve(result).catch((error) => {
|
|
5658
|
-
if (event !== "error")
|
|
5659
|
-
this.#emitError(error);
|
|
5660
|
-
});
|
|
5661
|
-
} catch (error) {
|
|
5662
|
-
if (event !== "error")
|
|
5663
|
-
this.#emitError(error);
|
|
5664
|
-
}
|
|
5665
|
-
}
|
|
7713
|
+
this.#events.emit(event, data);
|
|
5666
7714
|
}
|
|
5667
7715
|
#setState(next) {
|
|
5668
7716
|
if (this.state === next)
|
|
@@ -5675,14 +7723,12 @@ class Gateway {
|
|
|
5675
7723
|
|
|
5676
7724
|
// packages/core/src/index.ts
|
|
5677
7725
|
class EventEmitter2 {
|
|
5678
|
-
#listeners =
|
|
7726
|
+
#listeners = {};
|
|
7727
|
+
redactSecrets = (text) => text;
|
|
5679
7728
|
on(event, listener) {
|
|
5680
7729
|
if (typeof listener !== "function")
|
|
5681
7730
|
throw new TypeError("Event listener must be a function.");
|
|
5682
|
-
|
|
5683
|
-
if (!listeners)
|
|
5684
|
-
this.#listeners.set(event, listeners = new Set);
|
|
5685
|
-
listeners.add(listener);
|
|
7731
|
+
(this.#listeners[event] ??= new Set).add(listener);
|
|
5686
7732
|
return this;
|
|
5687
7733
|
}
|
|
5688
7734
|
once(event, listener) {
|
|
@@ -5693,7 +7739,7 @@ class EventEmitter2 {
|
|
|
5693
7739
|
return this.on(event, wrapped);
|
|
5694
7740
|
}
|
|
5695
7741
|
off(event, listener) {
|
|
5696
|
-
this.#listeners
|
|
7742
|
+
this.#listeners[event]?.delete(listener);
|
|
5697
7743
|
return this;
|
|
5698
7744
|
}
|
|
5699
7745
|
removeListener(event, listener) {
|
|
@@ -5701,13 +7747,13 @@ class EventEmitter2 {
|
|
|
5701
7747
|
}
|
|
5702
7748
|
removeAllListeners(event) {
|
|
5703
7749
|
if (event === undefined)
|
|
5704
|
-
this.#listeners
|
|
7750
|
+
this.#listeners = {};
|
|
5705
7751
|
else
|
|
5706
|
-
this.#listeners
|
|
7752
|
+
delete this.#listeners[event];
|
|
5707
7753
|
return this;
|
|
5708
7754
|
}
|
|
5709
7755
|
emit(event, ...args) {
|
|
5710
|
-
const listeners = this.#listeners
|
|
7756
|
+
const listeners = this.#listeners[event];
|
|
5711
7757
|
if (!listeners?.size)
|
|
5712
7758
|
return false;
|
|
5713
7759
|
for (const listener of [...listeners]) {
|
|
@@ -5723,28 +7769,27 @@ class EventEmitter2 {
|
|
|
5723
7769
|
}
|
|
5724
7770
|
#handleError(event, error) {
|
|
5725
7771
|
const normalized = error instanceof Error ? error : new Error(String(error), { cause: error });
|
|
5726
|
-
const
|
|
5727
|
-
|
|
5728
|
-
];
|
|
7772
|
+
const errorListeners = this.#listeners["error" /* Error */];
|
|
7773
|
+
const listeners = event === "error" /* Error */ ? [] : [...errorListeners ?? []];
|
|
5729
7774
|
if (listeners.length === 0)
|
|
5730
|
-
return warnListenerError(event, normalized);
|
|
7775
|
+
return warnListenerError(event, normalized, this.redactSecrets);
|
|
5731
7776
|
for (const listener of listeners) {
|
|
5732
7777
|
try {
|
|
5733
7778
|
const result = listener(normalized);
|
|
5734
7779
|
if (result && typeof result.then === "function")
|
|
5735
|
-
Promise.resolve(result).catch((failure) => warnListenerError("error" /* Error */, failure));
|
|
7780
|
+
Promise.resolve(result).catch((failure) => warnListenerError("error" /* Error */, failure, this.redactSecrets));
|
|
5736
7781
|
} catch (failure) {
|
|
5737
|
-
warnListenerError("error" /* Error */, failure);
|
|
7782
|
+
warnListenerError("error" /* Error */, failure, this.redactSecrets);
|
|
5738
7783
|
}
|
|
5739
7784
|
}
|
|
5740
7785
|
}
|
|
5741
7786
|
}
|
|
5742
|
-
function warnListenerError(event, error) {
|
|
7787
|
+
function warnListenerError(event, error, redact = (text) => text) {
|
|
5743
7788
|
const failure = error instanceof Error ? error : new Error(String(error));
|
|
5744
|
-
process.emitWarning(`A "${String(event)}" listener threw and no error listener handled it: ${failure.message}
|
|
7789
|
+
process.emitWarning(redact(`A "${String(event)}" listener threw and no error listener handled it: ${failure.message}`), {
|
|
5745
7790
|
type: "LunibeeWarning",
|
|
5746
7791
|
code: "LUNIBEE_UNHANDLED_LISTENER_ERROR",
|
|
5747
|
-
detail: failure.stack
|
|
7792
|
+
detail: failure.stack === undefined ? undefined : redact(failure.stack)
|
|
5748
7793
|
});
|
|
5749
7794
|
}
|
|
5750
7795
|
|
|
@@ -5756,7 +7801,13 @@ class Client extends EventEmitter2 {
|
|
|
5756
7801
|
channels;
|
|
5757
7802
|
stageInstances;
|
|
5758
7803
|
application;
|
|
7804
|
+
#api;
|
|
7805
|
+
get api() {
|
|
7806
|
+
return this.#api ??= createApi(this.rest);
|
|
7807
|
+
}
|
|
7808
|
+
commands = new CommandRegistry(this);
|
|
5759
7809
|
monetization;
|
|
7810
|
+
applicationEmojis;
|
|
5760
7811
|
get ws() {
|
|
5761
7812
|
return this.#gateway;
|
|
5762
7813
|
}
|
|
@@ -5766,6 +7817,10 @@ class Client extends EventEmitter2 {
|
|
|
5766
7817
|
user;
|
|
5767
7818
|
readyAt;
|
|
5768
7819
|
state = "idle";
|
|
7820
|
+
redactSecrets = (text) => {
|
|
7821
|
+
const token = this.options.token;
|
|
7822
|
+
return token && token.length >= 8 ? text.split(token).join("[token]") : text;
|
|
7823
|
+
};
|
|
5769
7824
|
get token() {
|
|
5770
7825
|
return this.state === "destroyed" ? null : this.options.token ?? null;
|
|
5771
7826
|
}
|
|
@@ -5781,9 +7836,26 @@ class Client extends EventEmitter2 {
|
|
|
5781
7836
|
setPresence(data) {
|
|
5782
7837
|
return this.#gateway.setPresence(data);
|
|
5783
7838
|
}
|
|
7839
|
+
setActivity(name, options = {}) {
|
|
7840
|
+
const type = options.type ?? ActivityEnum.Playing;
|
|
7841
|
+
return this.setPresence({
|
|
7842
|
+
status: options.status ?? "online",
|
|
7843
|
+
activities: name === null ? [] : [
|
|
7844
|
+
{
|
|
7845
|
+
name,
|
|
7846
|
+
type,
|
|
7847
|
+
url: options.url,
|
|
7848
|
+
state: options.state ?? (type === ActivityEnum.Custom ? name : undefined)
|
|
7849
|
+
}
|
|
7850
|
+
]
|
|
7851
|
+
});
|
|
7852
|
+
}
|
|
5784
7853
|
setVoiceState(data) {
|
|
5785
7854
|
return this.#gateway.setVoiceState(data);
|
|
5786
7855
|
}
|
|
7856
|
+
sendVoiceState(guildId, channelId, options = {}) {
|
|
7857
|
+
return this.#gateway.sendVoiceState(guildId, channelId, options);
|
|
7858
|
+
}
|
|
5787
7859
|
requestGuildMembers(data) {
|
|
5788
7860
|
return this.#gateway.requestGuildMembers(data);
|
|
5789
7861
|
}
|
|
@@ -5801,6 +7873,7 @@ class Client extends EventEmitter2 {
|
|
|
5801
7873
|
members: true,
|
|
5802
7874
|
roles: true,
|
|
5803
7875
|
emojis: true,
|
|
7876
|
+
presences: false,
|
|
5804
7877
|
...options.cache
|
|
5805
7878
|
};
|
|
5806
7879
|
this.users = new UserManager(this.rest);
|
|
@@ -5812,7 +7885,23 @@ class Client extends EventEmitter2 {
|
|
|
5812
7885
|
this.stageInstances = new StageInstanceManager(this.rest);
|
|
5813
7886
|
const placeholderAppCommands = new ApplicationCommandManager(this.rest, "0");
|
|
5814
7887
|
this.application = { commands: placeholderAppCommands };
|
|
5815
|
-
this.#resourceContext =
|
|
7888
|
+
this.#resourceContext = this.#createResourceContext();
|
|
7889
|
+
this.guilds.attachContext(this.#resourceContext);
|
|
7890
|
+
this.#gateway = new Gateway({
|
|
7891
|
+
token: options.token,
|
|
7892
|
+
intents: options.intents,
|
|
7893
|
+
...options.compress === undefined ? {} : { compress: options.compress },
|
|
7894
|
+
...options.gateway
|
|
7895
|
+
});
|
|
7896
|
+
this.#wireLifecycle();
|
|
7897
|
+
this.#wireMessages();
|
|
7898
|
+
this.#wireGuilds();
|
|
7899
|
+
this.#wireGuildFeatures();
|
|
7900
|
+
this.#wireChannels();
|
|
7901
|
+
this.#wireMisc();
|
|
7902
|
+
}
|
|
7903
|
+
#createResourceContext() {
|
|
7904
|
+
return {
|
|
5816
7905
|
sendMessage: (channelId, options) => this.channels.send(channelId, options),
|
|
5817
7906
|
editMessage: (channelId, messageId, options) => this.channels.editMessage(channelId, messageId, options),
|
|
5818
7907
|
deleteMessage: (channelId, messageId, reason) => this.channels.deleteMessage(channelId, messageId, reason),
|
|
@@ -5826,10 +7915,13 @@ class Client extends EventEmitter2 {
|
|
|
5826
7915
|
pinMessage: (channelId, messageId, reason) => this.channels.pinMessage(channelId, messageId, reason),
|
|
5827
7916
|
unpinMessage: (channelId, messageId, reason) => this.channels.unpinMessage(channelId, messageId, reason),
|
|
5828
7917
|
collectInteractions: (options) => this.createCollector("interactionCreate" /* InteractionCreate */, options),
|
|
5829
|
-
memberPermissions: (guildId, memberId, roleIds, channelId) => this.#memberPermissions(guildId, memberId, roleIds, channelId),
|
|
7918
|
+
memberPermissions: (guildId, memberId, roleIds, channelId, timedOutUntil) => this.#memberPermissions(guildId, memberId, roleIds, channelId, timedOutUntil),
|
|
5830
7919
|
kickMember: (guildId, userId, reason) => this.guilds.members(guildId).kick(userId, reason),
|
|
5831
7920
|
banMember: (guildId, userId, options) => this.guilds.members(guildId).ban(userId, options),
|
|
5832
|
-
editMember: (guildId, userId, options, reason) => this.guilds.members(guildId).edit(userId,
|
|
7921
|
+
editMember: (guildId, userId, options, reason) => this.guilds.members(guildId).edit(userId, {
|
|
7922
|
+
...options,
|
|
7923
|
+
reason: typeof options.reason === "string" ? options.reason : reason
|
|
7924
|
+
}),
|
|
5833
7925
|
addMemberRole: (guildId, userId, roleId, reason) => this.guilds.members(guildId).addRole(userId, roleId, reason),
|
|
5834
7926
|
removeMemberRole: (guildId, userId, roleId, reason) => this.guilds.members(guildId).removeRole(userId, roleId, reason),
|
|
5835
7927
|
editPermissionOverwrite: async (channelId, targetId, changes, options) => {
|
|
@@ -5849,12 +7941,8 @@ class Client extends EventEmitter2 {
|
|
|
5849
7941
|
return this.channels.permissionOverwrites(channelId).update(targetId, bits, options);
|
|
5850
7942
|
}
|
|
5851
7943
|
};
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
token: options.token,
|
|
5855
|
-
intents: options.intents,
|
|
5856
|
-
...options.gateway
|
|
5857
|
-
});
|
|
7944
|
+
}
|
|
7945
|
+
#wireLifecycle() {
|
|
5858
7946
|
this.#gateway.on("READY", (data) => {
|
|
5859
7947
|
const ready = data;
|
|
5860
7948
|
this.user = ready.user;
|
|
@@ -5865,6 +7953,8 @@ class Client extends EventEmitter2 {
|
|
|
5865
7953
|
this.application.commands = new ApplicationCommandManager(this.rest, appId);
|
|
5866
7954
|
if (this.monetization?.applicationId !== appId)
|
|
5867
7955
|
this.monetization = new MonetizationManager(this.rest, appId);
|
|
7956
|
+
if (this.applicationEmojis?.applicationId !== appId)
|
|
7957
|
+
this.applicationEmojis = new ApplicationEmojiManager(this.rest, appId);
|
|
5868
7958
|
this.emit("ready" /* Ready */, this.user);
|
|
5869
7959
|
});
|
|
5870
7960
|
this.#gateway.on("RESUMED", () => {
|
|
@@ -5880,6 +7970,8 @@ class Client extends EventEmitter2 {
|
|
|
5880
7970
|
this.state = "idle";
|
|
5881
7971
|
this.emit("close" /* Close */, data);
|
|
5882
7972
|
});
|
|
7973
|
+
}
|
|
7974
|
+
#wireMessages() {
|
|
5883
7975
|
this.#gateway.on("MESSAGE_CREATE", (data) => {
|
|
5884
7976
|
const payload = data;
|
|
5885
7977
|
const message = new Message(payload, this.#resourceContext);
|
|
@@ -5899,7 +7991,7 @@ class Client extends EventEmitter2 {
|
|
|
5899
7991
|
const previous = messages?.cache.peek(message.id);
|
|
5900
7992
|
if (previous)
|
|
5901
7993
|
messages.cache.set(message.id, message);
|
|
5902
|
-
this.emit("messageUpdate" /* MessageUpdate */, message, previous);
|
|
7994
|
+
this.emit("messageUpdate" /* MessageUpdate */, message, previous ?? null);
|
|
5903
7995
|
});
|
|
5904
7996
|
this.#gateway.on("MESSAGE_DELETE", (data) => {
|
|
5905
7997
|
const payload = data;
|
|
@@ -5927,6 +8019,8 @@ class Client extends EventEmitter2 {
|
|
|
5927
8019
|
this.#gateway.on("MESSAGE_REACTION_REMOVE_EMOJI", (data) => this.emit("messageReactionRemoveEmoji" /* MessageReactionRemoveEmoji */, data));
|
|
5928
8020
|
this.#gateway.on("MESSAGE_POLL_VOTE_ADD", (data) => this.emit("messagePollVoteAdd" /* MessagePollVoteAdd */, data));
|
|
5929
8021
|
this.#gateway.on("MESSAGE_POLL_VOTE_REMOVE", (data) => this.emit("messagePollVoteRemove" /* MessagePollVoteRemove */, data));
|
|
8022
|
+
}
|
|
8023
|
+
#wireGuilds() {
|
|
5930
8024
|
this.#gateway.on("GUILD_CREATE", (data) => {
|
|
5931
8025
|
const payload = data;
|
|
5932
8026
|
if (payload.unavailable) {
|
|
@@ -6027,6 +8121,8 @@ class Client extends EventEmitter2 {
|
|
|
6027
8121
|
roles.delete(event.role_id);
|
|
6028
8122
|
this.emit("guildRoleDelete" /* GuildRoleDelete */, event, removed);
|
|
6029
8123
|
});
|
|
8124
|
+
}
|
|
8125
|
+
#wireGuildFeatures() {
|
|
6030
8126
|
this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => {
|
|
6031
8127
|
const event = data;
|
|
6032
8128
|
let previous = null;
|
|
@@ -6097,8 +8193,10 @@ class Client extends EventEmitter2 {
|
|
|
6097
8193
|
});
|
|
6098
8194
|
this.#gateway.on("GUILD_SCHEDULED_EVENT_UPDATE", (data) => {
|
|
6099
8195
|
const event = data;
|
|
6100
|
-
this.guilds.scheduledEvents(event.guild_id)
|
|
6101
|
-
|
|
8196
|
+
const events = this.guilds.scheduledEvents(event.guild_id);
|
|
8197
|
+
const previous = events.get(event.id) ?? null;
|
|
8198
|
+
events.set(event.id, event);
|
|
8199
|
+
this.emit("guildScheduledEventUpdate" /* GuildScheduledEventUpdate */, event, previous);
|
|
6102
8200
|
});
|
|
6103
8201
|
this.#gateway.on("GUILD_SCHEDULED_EVENT_DELETE", (data) => {
|
|
6104
8202
|
const event = data;
|
|
@@ -6114,8 +8212,10 @@ class Client extends EventEmitter2 {
|
|
|
6114
8212
|
});
|
|
6115
8213
|
this.#gateway.on("AUTO_MODERATION_RULE_UPDATE", (data) => {
|
|
6116
8214
|
const rule = data;
|
|
6117
|
-
this.guilds.autoModerationRules(rule.guild_id)
|
|
6118
|
-
|
|
8215
|
+
const rules = this.guilds.autoModerationRules(rule.guild_id);
|
|
8216
|
+
const previous = rules.get(rule.id) ?? null;
|
|
8217
|
+
rules.set(rule.id, rule);
|
|
8218
|
+
this.emit("autoModerationRuleUpdate" /* AutoModerationRuleUpdate */, rule, previous);
|
|
6119
8219
|
});
|
|
6120
8220
|
this.#gateway.on("AUTO_MODERATION_RULE_DELETE", (data) => {
|
|
6121
8221
|
const rule = data;
|
|
@@ -6123,6 +8223,8 @@ class Client extends EventEmitter2 {
|
|
|
6123
8223
|
this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, rule);
|
|
6124
8224
|
});
|
|
6125
8225
|
this.#gateway.on("AUTO_MODERATION_ACTION_EXECUTION", (data) => this.emit("autoModerationActionExecution" /* AutoModerationActionExecution */, data));
|
|
8226
|
+
}
|
|
8227
|
+
#wireChannels() {
|
|
6126
8228
|
this.#gateway.on("CHANNEL_CREATE", (data) => {
|
|
6127
8229
|
const channel = this.channels.upsert(data);
|
|
6128
8230
|
this.emit("channelCreate" /* ChannelCreate */, channel);
|
|
@@ -6169,8 +8271,9 @@ class Client extends EventEmitter2 {
|
|
|
6169
8271
|
});
|
|
6170
8272
|
this.#gateway.on("STAGE_INSTANCE_UPDATE", (data) => {
|
|
6171
8273
|
const stage = data;
|
|
8274
|
+
const previous = this.stageInstances.get(stage.channel_id) ?? null;
|
|
6172
8275
|
this.stageInstances.set(stage.channel_id, stage);
|
|
6173
|
-
this.emit("stageInstanceUpdate" /* StageInstanceUpdate */, stage);
|
|
8276
|
+
this.emit("stageInstanceUpdate" /* StageInstanceUpdate */, stage, previous);
|
|
6174
8277
|
});
|
|
6175
8278
|
this.#gateway.on("STAGE_INSTANCE_DELETE", (data) => {
|
|
6176
8279
|
const stage = data;
|
|
@@ -6190,14 +8293,26 @@ class Client extends EventEmitter2 {
|
|
|
6190
8293
|
this.emit("inviteDelete" /* InviteDelete */, invite);
|
|
6191
8294
|
});
|
|
6192
8295
|
this.#gateway.on("WEBHOOKS_UPDATE", (data) => this.emit("webhooksUpdate" /* WebhooksUpdate */, data));
|
|
8296
|
+
}
|
|
8297
|
+
#wireMisc() {
|
|
6193
8298
|
this.#gateway.on("VOICE_STATE_UPDATE", (data) => {
|
|
6194
8299
|
const state = data;
|
|
8300
|
+
const previous = state.guild_id ? this.guilds.voiceStates(state.guild_id).get(state.user_id) ?? null : null;
|
|
6195
8301
|
if (state.guild_id)
|
|
6196
8302
|
this.#storeVoiceState(state.guild_id, state);
|
|
6197
|
-
this.emit("voiceStateUpdate" /* VoiceStateUpdate */, state);
|
|
8303
|
+
this.emit("voiceStateUpdate" /* VoiceStateUpdate */, state, previous);
|
|
6198
8304
|
});
|
|
6199
8305
|
this.#gateway.on("VOICE_SERVER_UPDATE", (data) => this.emit("voiceServerUpdate" /* VoiceServerUpdate */, data));
|
|
6200
|
-
this.#gateway.on("PRESENCE_UPDATE", (data) =>
|
|
8306
|
+
this.#gateway.on("PRESENCE_UPDATE", (data) => {
|
|
8307
|
+
const presence = data;
|
|
8308
|
+
let previous = null;
|
|
8309
|
+
if (this.#cache.presences && presence.guild_id) {
|
|
8310
|
+
const presences = this.guilds.presences(presence.guild_id);
|
|
8311
|
+
previous = presences.get(presence.user.id) ?? null;
|
|
8312
|
+
presences.set(presence.user.id, presence);
|
|
8313
|
+
}
|
|
8314
|
+
this.emit("presenceUpdate" /* PresenceUpdate */, presence, previous);
|
|
8315
|
+
});
|
|
6201
8316
|
this.#gateway.on("TYPING_START", (data) => this.emit("typingStart" /* TypingStart */, data));
|
|
6202
8317
|
this.#gateway.on("INTERACTION_CREATE", (data) => this.emit("interactionCreate" /* InteractionCreate */, createInteraction(this, data)));
|
|
6203
8318
|
this.#gateway.on("RAW", (data) => this.emit("raw" /* Raw */, data));
|
|
@@ -6262,10 +8377,28 @@ class Client extends EventEmitter2 {
|
|
|
6262
8377
|
collector.onDispose(() => this.off(event, listener));
|
|
6263
8378
|
return collector;
|
|
6264
8379
|
}
|
|
8380
|
+
guild(id) {
|
|
8381
|
+
return new GuildHandle(this, id);
|
|
8382
|
+
}
|
|
8383
|
+
channel(id) {
|
|
8384
|
+
return new ChannelHandle(this, id);
|
|
8385
|
+
}
|
|
8386
|
+
person(id) {
|
|
8387
|
+
return new UserHandle(this, id);
|
|
8388
|
+
}
|
|
8389
|
+
member(guildId, userId) {
|
|
8390
|
+
return new MemberHandle(this, guildId, userId);
|
|
8391
|
+
}
|
|
8392
|
+
role(guildId, roleId) {
|
|
8393
|
+
return new RoleHandle(this, guildId, roleId);
|
|
8394
|
+
}
|
|
8395
|
+
message(channelId, messageId) {
|
|
8396
|
+
return new MessageHandle(this, channelId, messageId);
|
|
8397
|
+
}
|
|
6265
8398
|
get resourceContext() {
|
|
6266
8399
|
return this.#resourceContext;
|
|
6267
8400
|
}
|
|
6268
|
-
#memberPermissions(guildId, memberId, roleIds, channelId) {
|
|
8401
|
+
#memberPermissions(guildId, memberId, roleIds, channelId, timedOutUntil) {
|
|
6269
8402
|
const guild = this.guilds.get(guildId);
|
|
6270
8403
|
if (!guild)
|
|
6271
8404
|
return null;
|
|
@@ -6282,7 +8415,8 @@ class Client extends EventEmitter2 {
|
|
|
6282
8415
|
memberId,
|
|
6283
8416
|
memberRoleIds: [...roleIds],
|
|
6284
8417
|
roles: this.guilds.roles(guildId).values(),
|
|
6285
|
-
overwrites: channel?.permissionOverwrites
|
|
8418
|
+
overwrites: channel?.permissionOverwrites,
|
|
8419
|
+
timedOutUntil
|
|
6286
8420
|
});
|
|
6287
8421
|
}
|
|
6288
8422
|
permissionsFor(memberId, guildOrChannelId) {
|
|
@@ -6303,7 +8437,8 @@ class Client extends EventEmitter2 {
|
|
|
6303
8437
|
memberId,
|
|
6304
8438
|
memberRoleIds: member.roleIds,
|
|
6305
8439
|
roles: this.guilds.roles(guildId).values(),
|
|
6306
|
-
overwrites: channel?.permissionOverwrites
|
|
8440
|
+
overwrites: channel?.permissionOverwrites,
|
|
8441
|
+
timedOutUntil: member.timedOutUntil
|
|
6307
8442
|
});
|
|
6308
8443
|
}
|
|
6309
8444
|
fetchDefaultSoundboardSounds() {
|
|
@@ -6351,10 +8486,10 @@ class Client extends EventEmitter2 {
|
|
|
6351
8486
|
return Promise.reject(new Error("Client is unauthenticated."));
|
|
6352
8487
|
return this.rest.delete(Routes.interactionOriginalResponse(this.user.id, token));
|
|
6353
8488
|
}
|
|
6354
|
-
followUpInteraction(token, data) {
|
|
8489
|
+
async followUpInteraction(token, data) {
|
|
6355
8490
|
if (!this.user)
|
|
6356
8491
|
return Promise.reject(new Error("Client is unauthenticated."));
|
|
6357
|
-
return this.rest.post(
|
|
8492
|
+
return this.rest.post(Routes.webhook(this.user.id, token), toRequest(data, this.options.allowedMentions));
|
|
6358
8493
|
}
|
|
6359
8494
|
interactionWebhookMessage(method, applicationId, token, messageId, data) {
|
|
6360
8495
|
const path = messageId === "@original" ? Routes.interactionOriginalResponse(applicationId, token) : Routes.webhookMessage(applicationId, token, messageId);
|
|
@@ -6364,11 +8499,11 @@ class Client extends EventEmitter2 {
|
|
|
6364
8499
|
return this.rest.patch(path, data ? toRequest(data, this.options.allowedMentions) : data);
|
|
6365
8500
|
return this.rest.delete(path);
|
|
6366
8501
|
}
|
|
6367
|
-
fetchWebhook(id, token) {
|
|
6368
|
-
return this.rest.get(
|
|
8502
|
+
async fetchWebhook(id, token) {
|
|
8503
|
+
return this.rest.get(Routes.webhook(id, token));
|
|
6369
8504
|
}
|
|
6370
|
-
fetchGuildPreview(guildId) {
|
|
6371
|
-
return this.rest.get(
|
|
8505
|
+
async fetchGuildPreview(guildId) {
|
|
8506
|
+
return this.rest.get(Routes.guildPreview(guildId));
|
|
6372
8507
|
}
|
|
6373
8508
|
fetchVoiceRegions() {
|
|
6374
8509
|
return this.rest.get("/voice/regions");
|
|
@@ -6382,11 +8517,11 @@ class Client extends EventEmitter2 {
|
|
|
6382
8517
|
const qs = query.toString();
|
|
6383
8518
|
return this.rest.get(`/invites/${encodeURIComponent(code)}${qs ? `?${qs}` : ""}`);
|
|
6384
8519
|
}
|
|
6385
|
-
fetchSticker(id) {
|
|
6386
|
-
return this.rest.get(
|
|
8520
|
+
async fetchSticker(id) {
|
|
8521
|
+
return this.rest.get(Routes.sticker(id));
|
|
6387
8522
|
}
|
|
6388
8523
|
fetchPremiumStickerPacks() {
|
|
6389
|
-
return this.rest.get(
|
|
8524
|
+
return this.rest.get(Routes.stickerPacks());
|
|
6390
8525
|
}
|
|
6391
8526
|
fetchGuildTemplate(code) {
|
|
6392
8527
|
return this.rest.get(`/guilds/templates/${encodeURIComponent(code)}`);
|
|
@@ -6405,23 +8540,34 @@ class Client extends EventEmitter2 {
|
|
|
6405
8540
|
}
|
|
6406
8541
|
}
|
|
6407
8542
|
export {
|
|
8543
|
+
ChannelHandle,
|
|
6408
8544
|
Client,
|
|
6409
8545
|
ClientEvent,
|
|
6410
8546
|
Collector,
|
|
8547
|
+
CommandRegistry,
|
|
6411
8548
|
ClientEvent as Events,
|
|
6412
8549
|
GatewayIntentBits,
|
|
8550
|
+
GuildHandle,
|
|
6413
8551
|
IntentBits,
|
|
6414
8552
|
Intents,
|
|
6415
8553
|
IntentsBitField,
|
|
8554
|
+
MemberHandle,
|
|
8555
|
+
MessageHandle,
|
|
6416
8556
|
Permission,
|
|
6417
8557
|
PermissionFlagsBits,
|
|
6418
8558
|
PermissionOverwriteEnum,
|
|
6419
|
-
PermissionOverwriteType,
|
|
6420
8559
|
PermissionSet,
|
|
6421
8560
|
Permissions,
|
|
6422
8561
|
PermissionsBitField,
|
|
8562
|
+
RoleHandle,
|
|
8563
|
+
UserHandle,
|
|
8564
|
+
channelCreatePayload,
|
|
8565
|
+
command,
|
|
6423
8566
|
computePermissions,
|
|
8567
|
+
createApi,
|
|
8568
|
+
option,
|
|
8569
|
+
parseDuration,
|
|
6424
8570
|
resolveGatewayIntents
|
|
6425
8571
|
};
|
|
6426
8572
|
|
|
6427
|
-
//# debugId=
|
|
8573
|
+
//# debugId=EEC9EA7D2E19B5EE64756E2164756E21
|