chapterjs 0.3.0 → 0.4.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 +2 -2
- package/dist/cli/build.js +14 -1
- package/dist/cli/dev.js +29 -1
- package/dist/cli/env.d.ts +5 -0
- package/dist/cli/env.js +39 -3
- package/dist/cli/project.d.ts +30 -7
- package/dist/cli/project.js +85 -11
- package/dist/cli/redis.d.ts +23 -0
- package/dist/cli/redis.js +57 -0
- package/dist/cli/start.js +43 -17
- package/dist/cli/test.js +4 -2
- package/dist/events/registry.d.ts +252 -239
- package/dist/events/registry.js +125 -100
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -0
- package/dist/ranking/declaration.d.ts +12 -0
- package/dist/ranking/declaration.js +48 -0
- package/dist/ranking/ranking.d.ts +102 -0
- package/dist/ranking/ranking.js +129 -0
- package/dist/redis/client.d.ts +36 -0
- package/dist/redis/client.js +252 -0
- package/dist/redis/protocol.d.ts +22 -0
- package/dist/redis/protocol.js +99 -0
- package/dist/redis/url.d.ts +24 -0
- package/dist/redis/url.js +50 -0
- package/dist/store/backend.d.ts +49 -4
- package/dist/store/backend.js +66 -11
- package/dist/store/declaration.d.ts +3 -0
- package/dist/store/declaration.js +8 -3
- package/dist/store/file-backend.d.ts +3 -1
- package/dist/store/file-backend.js +29 -0
- package/dist/store/ipc-backend.d.ts +24 -1
- package/dist/store/ipc-backend.js +49 -0
- package/dist/store/memory-backend.d.ts +4 -2
- package/dist/store/memory-backend.js +27 -1
- package/dist/store/ranking-backend.d.ts +45 -0
- package/dist/store/ranking-backend.js +82 -0
- package/dist/store/redis-backend.d.ts +38 -0
- package/dist/store/redis-backend.js +245 -0
- package/dist/store/redis-ranking.d.ts +15 -0
- package/dist/store/redis-ranking.js +69 -0
- package/dist/store/scope.d.ts +11 -0
- package/dist/store/scope.js +23 -0
- package/dist/store/store.d.ts +39 -5
- package/dist/store/store.js +79 -32
- package/dist/structures/invite.d.ts +6 -0
- package/dist/structures/invite.js +11 -0
- package/package.json +1 -1
package/dist/events/registry.js
CHANGED
|
@@ -16,13 +16,15 @@ const channel = (on) => ({
|
|
|
16
16
|
on,
|
|
17
17
|
build: (ctx, data) => {
|
|
18
18
|
const found = ctx.cache.channels.get(data.id);
|
|
19
|
-
return found ? { channel: found } : null;
|
|
19
|
+
return found ? { channel: found, guild: found.guild } : null;
|
|
20
20
|
},
|
|
21
21
|
});
|
|
22
22
|
const deletedChannel = (on) => ({
|
|
23
23
|
on,
|
|
24
24
|
before: (ctx, data) => ctx.cache.channels.get(data.id) ?? null,
|
|
25
|
-
build: (_ctx, _data, { before }) => before
|
|
25
|
+
build: (_ctx, _data, { before }) => before
|
|
26
|
+
? { channel: before, guild: before.guild }
|
|
27
|
+
: null,
|
|
26
28
|
});
|
|
27
29
|
/**
|
|
28
30
|
* Discord refused what an event needs before it can be given to its files:
|
|
@@ -95,14 +97,19 @@ const placeAndUser = (ctx, data, userId) => {
|
|
|
95
97
|
};
|
|
96
98
|
/** Who did it: what `prepare` got, or else what the bot knows. */
|
|
97
99
|
const userFrom = (ctx, prepared, id) => prepared ?? ctx.cache.users.get(id) ?? null;
|
|
98
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* Where something happened in a server or in private, as the bot knows
|
|
102
|
+
* it: `at` goes in the object of the event, `guild` next to it.
|
|
103
|
+
*/
|
|
99
104
|
const placeOf = (ctx, data) => {
|
|
100
105
|
const found = ctx.cache.channels.get(data.channel_id);
|
|
101
106
|
const guildId = data.guild_id ?? found?.guildId ?? null;
|
|
102
107
|
return {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
108
|
+
at: {
|
|
109
|
+
channelId: data.channel_id,
|
|
110
|
+
channel: found?.isTextBased() ? found : null,
|
|
111
|
+
guildId,
|
|
112
|
+
},
|
|
106
113
|
guild: guildId ? (ctx.cache.guilds.get(guildId) ?? null) : null,
|
|
107
114
|
};
|
|
108
115
|
};
|
|
@@ -114,15 +121,15 @@ const rememberedMember = (guild, userId) => guild?.members.get(userId) ?? null;
|
|
|
114
121
|
* Whether a file wants something that happened in a server or in private:
|
|
115
122
|
* it listens there, and in a server what it is promised is there.
|
|
116
123
|
*/
|
|
117
|
-
const wantedPlace = (
|
|
118
|
-
const inGuild =
|
|
124
|
+
const wantedPlace = (about, guild, where, needsMember = false) => {
|
|
125
|
+
const inGuild = about.guildId !== null;
|
|
119
126
|
if (!listensThere(where, inGuild))
|
|
120
127
|
return false;
|
|
121
128
|
if (!inGuild)
|
|
122
129
|
return true;
|
|
123
|
-
return (
|
|
124
|
-
|
|
125
|
-
(!needsMember ||
|
|
130
|
+
return (guild !== null &&
|
|
131
|
+
about.channel !== null &&
|
|
132
|
+
(!needsMember || about.member != null));
|
|
126
133
|
};
|
|
127
134
|
/**
|
|
128
135
|
* Private messages, bots and webhooks only reach the files that asked for
|
|
@@ -152,9 +159,10 @@ const wantedMessage = ({ message }, options) => {
|
|
|
152
159
|
const message = (on) => ({
|
|
153
160
|
on,
|
|
154
161
|
prepare: channelOf,
|
|
155
|
-
build: (ctx, data) =>
|
|
156
|
-
message
|
|
157
|
-
|
|
162
|
+
build: (ctx, data) => {
|
|
163
|
+
const message = ctx.entities.message(data, data.guild_id);
|
|
164
|
+
return { message, guild: message.guild };
|
|
165
|
+
},
|
|
158
166
|
});
|
|
159
167
|
const member = (on) => ({
|
|
160
168
|
on,
|
|
@@ -226,12 +234,15 @@ const cleared = (on) => ({
|
|
|
226
234
|
on,
|
|
227
235
|
prepare: channelOf,
|
|
228
236
|
build: (ctx, data) => {
|
|
229
|
-
const
|
|
237
|
+
const { at, guild } = placeOf(ctx, data);
|
|
230
238
|
return {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
239
|
+
reactions: {
|
|
240
|
+
emoji: 'emoji' in data ? toCamelCase(data.emoji) : null,
|
|
241
|
+
messageId: data.message_id,
|
|
242
|
+
message: rememberedMessage(at.channel, data.message_id),
|
|
243
|
+
...at,
|
|
244
|
+
},
|
|
245
|
+
guild,
|
|
235
246
|
};
|
|
236
247
|
},
|
|
237
248
|
});
|
|
@@ -239,17 +250,20 @@ const vote = (on) => ({
|
|
|
239
250
|
on,
|
|
240
251
|
prepare: (ctx, data) => placeAndUser(ctx, data, data.user_id),
|
|
241
252
|
build: (ctx, data, { prepared }) => {
|
|
242
|
-
const
|
|
253
|
+
const { at, guild } = placeOf(ctx, data);
|
|
243
254
|
const user = userFrom(ctx, prepared, data.user_id);
|
|
244
255
|
if (!user)
|
|
245
256
|
return null;
|
|
246
257
|
return {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
258
|
+
vote: {
|
|
259
|
+
answerId: data.answer_id,
|
|
260
|
+
user,
|
|
261
|
+
member: rememberedMember(guild, data.user_id),
|
|
262
|
+
messageId: data.message_id,
|
|
263
|
+
message: rememberedMessage(at.channel, data.message_id),
|
|
264
|
+
...at,
|
|
265
|
+
},
|
|
266
|
+
guild,
|
|
253
267
|
};
|
|
254
268
|
},
|
|
255
269
|
});
|
|
@@ -283,7 +297,7 @@ const voice = (pick) => ({
|
|
|
283
297
|
: guild.members.get(data.user_id);
|
|
284
298
|
if (!picked || !member)
|
|
285
299
|
return null;
|
|
286
|
-
return { ...picked, member, guild };
|
|
300
|
+
return { voice: { ...picked, member }, guild };
|
|
287
301
|
},
|
|
288
302
|
});
|
|
289
303
|
const scheduled = (on) => ({
|
|
@@ -308,9 +322,11 @@ const interested = (on) => ({
|
|
|
308
322
|
if (!guild || !user)
|
|
309
323
|
return null;
|
|
310
324
|
return {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
325
|
+
interest: {
|
|
326
|
+
scheduledEventId: data.guild_scheduled_event_id,
|
|
327
|
+
user,
|
|
328
|
+
member: rememberedMember(guild, data.user_id),
|
|
329
|
+
},
|
|
314
330
|
guild,
|
|
315
331
|
};
|
|
316
332
|
},
|
|
@@ -322,7 +338,7 @@ const interested = (on) => ({
|
|
|
322
338
|
export const EVENTS = {
|
|
323
339
|
ready: { intents: 0, sources: [] },
|
|
324
340
|
messageCreate: {
|
|
325
|
-
guildOf:
|
|
341
|
+
guildOf: ofGuild,
|
|
326
342
|
// Without Message Content, the messages of others come empty.
|
|
327
343
|
intents: ({ where }) => messagesIn(where) | I.MessageContent,
|
|
328
344
|
options: { bots: 'boolean', where: PLACES },
|
|
@@ -330,7 +346,7 @@ export const EVENTS = {
|
|
|
330
346
|
sources: [message('MESSAGE_CREATE')],
|
|
331
347
|
},
|
|
332
348
|
messageUpdate: {
|
|
333
|
-
guildOf:
|
|
349
|
+
guildOf: ofGuild,
|
|
334
350
|
intents: ({ where }) => messagesIn(where) | I.MessageContent,
|
|
335
351
|
options: { bots: 'boolean', where: PLACES },
|
|
336
352
|
accepts: wantedMessage,
|
|
@@ -340,9 +356,7 @@ export const EVENTS = {
|
|
|
340
356
|
guildOf: ofGuild,
|
|
341
357
|
intents: ({ where }) => messagesIn(where),
|
|
342
358
|
options: { where: PLACES },
|
|
343
|
-
accepts: ({
|
|
344
|
-
// In a server, the server and the channel are promised.
|
|
345
|
-
(guildId === null || (guild !== null && channel !== null)),
|
|
359
|
+
accepts: ({ message, guild }, options) => wantedPlace(message, guild, options.where),
|
|
346
360
|
sources: [
|
|
347
361
|
{
|
|
348
362
|
on: 'MESSAGE_DELETE',
|
|
@@ -353,11 +367,13 @@ export const EVENTS = {
|
|
|
353
367
|
? (found.messages.get(data.id) ?? null)
|
|
354
368
|
: null;
|
|
355
369
|
},
|
|
356
|
-
build: (ctx, data, { before }) =>
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
370
|
+
build: (ctx, data, { before }) => {
|
|
371
|
+
const { at, guild } = placeOf(ctx, data);
|
|
372
|
+
return {
|
|
373
|
+
message: { id: data.id, ...at, before: before },
|
|
374
|
+
guild,
|
|
375
|
+
};
|
|
376
|
+
},
|
|
361
377
|
},
|
|
362
378
|
{
|
|
363
379
|
// Messages deleted together: one occurrence each.
|
|
@@ -368,12 +384,11 @@ export const EVENTS = {
|
|
|
368
384
|
return data.ids.map(id => found?.isTextBased() ? (found.messages.get(id) ?? null) : null);
|
|
369
385
|
},
|
|
370
386
|
build: (ctx, data, { before }) => {
|
|
371
|
-
const
|
|
387
|
+
const { at, guild } = placeOf(ctx, data);
|
|
372
388
|
const messages = before;
|
|
373
|
-
return data.ids.map((
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
message: messages[index] ?? null,
|
|
389
|
+
return data.ids.map((id, index) => ({
|
|
390
|
+
message: { id, ...at, before: messages[index] ?? null },
|
|
391
|
+
guild,
|
|
377
392
|
}));
|
|
378
393
|
},
|
|
379
394
|
},
|
|
@@ -392,21 +407,14 @@ export const EVENTS = {
|
|
|
392
407
|
memberLeave: {
|
|
393
408
|
guildOf: ofGuild,
|
|
394
409
|
intents: I.GuildMembers,
|
|
395
|
-
// "The member as it was" is a member the bot remembered.
|
|
396
|
-
remembers: { members: 1000 },
|
|
397
410
|
sources: [
|
|
398
411
|
{
|
|
399
412
|
on: 'GUILD_MEMBER_REMOVE',
|
|
400
|
-
|
|
401
|
-
build: (ctx, data, { before }) => {
|
|
413
|
+
build: (ctx, data) => {
|
|
402
414
|
const guild = findGuild(ctx, data.guild_id);
|
|
403
415
|
if (!guild)
|
|
404
416
|
return null;
|
|
405
|
-
return {
|
|
406
|
-
user: ctx.entities.user(data.user),
|
|
407
|
-
guild,
|
|
408
|
-
member: before,
|
|
409
|
-
};
|
|
417
|
+
return { user: ctx.entities.user(data.user), guild };
|
|
410
418
|
},
|
|
411
419
|
},
|
|
412
420
|
],
|
|
@@ -437,17 +445,17 @@ export const EVENTS = {
|
|
|
437
445
|
],
|
|
438
446
|
},
|
|
439
447
|
channelCreate: {
|
|
440
|
-
guildOf:
|
|
448
|
+
guildOf: ofGuild,
|
|
441
449
|
intents: I.Guilds,
|
|
442
450
|
sources: [channel('CHANNEL_CREATE'), channel('THREAD_CREATE')],
|
|
443
451
|
},
|
|
444
452
|
channelUpdate: {
|
|
445
|
-
guildOf:
|
|
453
|
+
guildOf: ofGuild,
|
|
446
454
|
intents: I.Guilds,
|
|
447
455
|
sources: [channel('CHANNEL_UPDATE'), channel('THREAD_UPDATE')],
|
|
448
456
|
},
|
|
449
457
|
channelDelete: {
|
|
450
|
-
guildOf:
|
|
458
|
+
guildOf: ofGuild,
|
|
451
459
|
intents: I.Guilds,
|
|
452
460
|
sources: [
|
|
453
461
|
deletedChannel('CHANNEL_DELETE'),
|
|
@@ -476,7 +484,7 @@ export const EVENTS = {
|
|
|
476
484
|
// Every role of a server is known: one that is not never was.
|
|
477
485
|
if (!guild || !before)
|
|
478
486
|
return null;
|
|
479
|
-
return {
|
|
487
|
+
return { role: before, guild };
|
|
480
488
|
},
|
|
481
489
|
},
|
|
482
490
|
],
|
|
@@ -544,7 +552,7 @@ export const EVENTS = {
|
|
|
544
552
|
channel: { id: channelId },
|
|
545
553
|
...(inviter ? { inviter } : {}),
|
|
546
554
|
});
|
|
547
|
-
return { invite,
|
|
555
|
+
return { invite, guild: place.guild };
|
|
548
556
|
},
|
|
549
557
|
},
|
|
550
558
|
],
|
|
@@ -558,7 +566,12 @@ export const EVENTS = {
|
|
|
558
566
|
prepare: channelOf,
|
|
559
567
|
build: (ctx, data) => {
|
|
560
568
|
const place = inviteChannel(ctx, data);
|
|
561
|
-
return place
|
|
569
|
+
return place
|
|
570
|
+
? {
|
|
571
|
+
invite: { code: data.code, channel: place.channel },
|
|
572
|
+
guild: place.guild,
|
|
573
|
+
}
|
|
574
|
+
: null;
|
|
562
575
|
},
|
|
563
576
|
},
|
|
564
577
|
],
|
|
@@ -583,15 +596,15 @@ export const EVENTS = {
|
|
|
583
596
|
guildOf: ofGuild,
|
|
584
597
|
intents: ({ where }) => reactionsIn(where),
|
|
585
598
|
options: { bots: 'boolean', where: PLACES },
|
|
586
|
-
accepts: (
|
|
587
|
-
(options.bots === true || !
|
|
599
|
+
accepts: ({ reaction, guild }, options) => wantedPlace(reaction, guild, options.where, true) &&
|
|
600
|
+
(options.bots === true || !reaction.user.bot),
|
|
588
601
|
sources: [
|
|
589
602
|
{
|
|
590
603
|
on: 'MESSAGE_REACTION_ADD',
|
|
591
604
|
// In a server, who reacted comes with the event.
|
|
592
605
|
prepare: (ctx, data) => placeAndUser(ctx, data, data.member?.user ? null : data.user_id),
|
|
593
606
|
build: (ctx, data, { prepared }) => {
|
|
594
|
-
const
|
|
607
|
+
const { at, guild } = placeOf(ctx, data);
|
|
595
608
|
const member = data.member && data.guild_id
|
|
596
609
|
? ctx.entities.member(data.guild_id, data.member)
|
|
597
610
|
: null;
|
|
@@ -599,14 +612,17 @@ export const EVENTS = {
|
|
|
599
612
|
if (!user)
|
|
600
613
|
return null;
|
|
601
614
|
return {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
615
|
+
reaction: {
|
|
616
|
+
emoji: toCamelCase(data.emoji),
|
|
617
|
+
user,
|
|
618
|
+
member,
|
|
619
|
+
burst: data.burst,
|
|
620
|
+
messageId: data.message_id,
|
|
621
|
+
message: rememberedMessage(at.channel, data.message_id),
|
|
622
|
+
messageAuthorId: data.message_author_id ?? null,
|
|
623
|
+
...at,
|
|
624
|
+
},
|
|
625
|
+
guild,
|
|
610
626
|
};
|
|
611
627
|
},
|
|
612
628
|
},
|
|
@@ -616,25 +632,28 @@ export const EVENTS = {
|
|
|
616
632
|
guildOf: ofGuild,
|
|
617
633
|
intents: ({ where }) => reactionsIn(where),
|
|
618
634
|
options: { bots: 'boolean', where: PLACES },
|
|
619
|
-
accepts: (
|
|
620
|
-
(options.bots === true || !
|
|
635
|
+
accepts: ({ reaction, guild }, options) => wantedPlace(reaction, guild, options.where) &&
|
|
636
|
+
(options.bots === true || !reaction.user.bot),
|
|
621
637
|
sources: [
|
|
622
638
|
{
|
|
623
639
|
on: 'MESSAGE_REACTION_REMOVE',
|
|
624
640
|
prepare: (ctx, data) => placeAndUser(ctx, data, data.user_id),
|
|
625
641
|
build: (ctx, data, { prepared }) => {
|
|
626
|
-
const
|
|
642
|
+
const { at, guild } = placeOf(ctx, data);
|
|
627
643
|
const user = userFrom(ctx, prepared, data.user_id);
|
|
628
644
|
if (!user)
|
|
629
645
|
return null;
|
|
630
646
|
return {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
647
|
+
reaction: {
|
|
648
|
+
emoji: toCamelCase(data.emoji),
|
|
649
|
+
user,
|
|
650
|
+
member: rememberedMember(guild, data.user_id),
|
|
651
|
+
burst: data.burst,
|
|
652
|
+
messageId: data.message_id,
|
|
653
|
+
message: rememberedMessage(at.channel, data.message_id),
|
|
654
|
+
...at,
|
|
655
|
+
},
|
|
656
|
+
guild,
|
|
638
657
|
};
|
|
639
658
|
},
|
|
640
659
|
},
|
|
@@ -644,7 +663,7 @@ export const EVENTS = {
|
|
|
644
663
|
guildOf: ofGuild,
|
|
645
664
|
intents: ({ where }) => reactionsIn(where),
|
|
646
665
|
options: { where: PLACES },
|
|
647
|
-
accepts: (
|
|
666
|
+
accepts: ({ reactions, guild }, options) => wantedPlace(reactions, guild, options.where),
|
|
648
667
|
sources: [
|
|
649
668
|
cleared('MESSAGE_REACTION_REMOVE_ALL'),
|
|
650
669
|
cleared('MESSAGE_REACTION_REMOVE_EMOJI'),
|
|
@@ -654,14 +673,14 @@ export const EVENTS = {
|
|
|
654
673
|
guildOf: ofGuild,
|
|
655
674
|
intents: ({ where }) => pollsIn(where),
|
|
656
675
|
options: { where: PLACES },
|
|
657
|
-
accepts: (
|
|
676
|
+
accepts: ({ vote, guild }, options) => wantedPlace(vote, guild, options.where),
|
|
658
677
|
sources: [vote('MESSAGE_POLL_VOTE_ADD')],
|
|
659
678
|
},
|
|
660
679
|
pollVoteRemove: {
|
|
661
680
|
guildOf: ofGuild,
|
|
662
681
|
intents: ({ where }) => pollsIn(where),
|
|
663
682
|
options: { where: PLACES },
|
|
664
|
-
accepts: (
|
|
683
|
+
accepts: ({ vote, guild }, options) => wantedPlace(vote, guild, options.where),
|
|
665
684
|
sources: [vote('MESSAGE_POLL_VOTE_REMOVE')],
|
|
666
685
|
},
|
|
667
686
|
typingStart: {
|
|
@@ -669,7 +688,7 @@ export const EVENTS = {
|
|
|
669
688
|
intents: ({ where }) => (where === 'dm' ? 0 : I.GuildMessageTyping) |
|
|
670
689
|
(where === 'dm' || where === 'both' ? I.DirectMessageTyping : 0),
|
|
671
690
|
options: { where: PLACES },
|
|
672
|
-
accepts: (
|
|
691
|
+
accepts: ({ typing, guild }, options) => wantedPlace(typing, guild, options.where, true),
|
|
673
692
|
sources: [
|
|
674
693
|
{
|
|
675
694
|
on: 'TYPING_START',
|
|
@@ -681,11 +700,15 @@ export const EVENTS = {
|
|
|
681
700
|
const user = member?.user ?? userFrom(ctx, prepared, data.user_id);
|
|
682
701
|
if (!user)
|
|
683
702
|
return null;
|
|
703
|
+
const { at, guild } = placeOf(ctx, data);
|
|
684
704
|
return {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
705
|
+
typing: {
|
|
706
|
+
user,
|
|
707
|
+
member,
|
|
708
|
+
startedAt: new Date(data.timestamp * 1000),
|
|
709
|
+
...at,
|
|
710
|
+
},
|
|
711
|
+
guild,
|
|
689
712
|
};
|
|
690
713
|
},
|
|
691
714
|
},
|
|
@@ -711,7 +734,7 @@ export const EVENTS = {
|
|
|
711
734
|
if (!added.member?.user)
|
|
712
735
|
continue;
|
|
713
736
|
const member = ctx.entities.member(data.guild_id, added.member);
|
|
714
|
-
joined.push({ member,
|
|
737
|
+
joined.push({ thread: place.thread, member, guild: place.guild });
|
|
715
738
|
}
|
|
716
739
|
return joined;
|
|
717
740
|
},
|
|
@@ -732,10 +755,10 @@ export const EVENTS = {
|
|
|
732
755
|
if (!place)
|
|
733
756
|
return null;
|
|
734
757
|
return (data.removed_member_ids ?? []).map(userId => ({
|
|
758
|
+
thread: place.thread,
|
|
735
759
|
userId,
|
|
736
|
-
user: ctx.cache.users.get(userId) ?? null,
|
|
737
760
|
member: rememberedMember(place.guild, userId),
|
|
738
|
-
|
|
761
|
+
guild: place.guild,
|
|
739
762
|
}));
|
|
740
763
|
},
|
|
741
764
|
},
|
|
@@ -745,14 +768,14 @@ export const EVENTS = {
|
|
|
745
768
|
guildOf: ofGuild,
|
|
746
769
|
intents: I.GuildVoiceStates,
|
|
747
770
|
sources: [
|
|
748
|
-
voice((was, now) => !was && now ? { channel: now.channel,
|
|
771
|
+
voice((was, now) => !was && now ? { channel: now.channel, state: stateOf(now) } : null),
|
|
749
772
|
],
|
|
750
773
|
},
|
|
751
774
|
voiceLeave: {
|
|
752
775
|
guildOf: ofGuild,
|
|
753
776
|
intents: I.GuildVoiceStates,
|
|
754
777
|
sources: [
|
|
755
|
-
voice((was, now) => was && !now ? { channel: was.channel,
|
|
778
|
+
voice((was, now) => was && !now ? { channel: was.channel, state: stateOf(was) } : null),
|
|
756
779
|
],
|
|
757
780
|
},
|
|
758
781
|
voiceMove: {
|
|
@@ -760,7 +783,7 @@ export const EVENTS = {
|
|
|
760
783
|
intents: I.GuildVoiceStates,
|
|
761
784
|
sources: [
|
|
762
785
|
voice((was, now) => was && now && was.channel.id !== now.channel.id
|
|
763
|
-
? { from: was.channel, to: now.channel,
|
|
786
|
+
? { from: was.channel, to: now.channel, state: stateOf(now) }
|
|
764
787
|
: null),
|
|
765
788
|
],
|
|
766
789
|
},
|
|
@@ -774,7 +797,7 @@ export const EVENTS = {
|
|
|
774
797
|
JSON.stringify(was.state) !== JSON.stringify(now.state)
|
|
775
798
|
? {
|
|
776
799
|
channel: now.channel,
|
|
777
|
-
|
|
800
|
+
state: stateOf(now),
|
|
778
801
|
before: stateOf(was),
|
|
779
802
|
}
|
|
780
803
|
: null),
|
|
@@ -797,10 +820,12 @@ export const EVENTS = {
|
|
|
797
820
|
? ctx.entities.user(raw)
|
|
798
821
|
: (ctx.cache.users.get(raw.id) ?? null);
|
|
799
822
|
return {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
823
|
+
presence: {
|
|
824
|
+
...toCamelCase(presence),
|
|
825
|
+
userId: raw.id,
|
|
826
|
+
user,
|
|
827
|
+
member: rememberedMember(guild, raw.id),
|
|
828
|
+
},
|
|
804
829
|
guild,
|
|
805
830
|
};
|
|
806
831
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type { ContainerOptions, LinkButtonOptions, MediaOptions, SeparatorOption
|
|
|
18
18
|
export type { ActionRowComponent, ButtonComponent, ContainerChild, ContainerComponent, FileComponent, GalleryComponent, MessageComponent, ModalComponent, Piece, SectionComponent, SelectComponent, SeparatorComponent, TextComponent, ThumbnailComponent, } from './components/instance.js';
|
|
19
19
|
export { event } from './events/event.js';
|
|
20
20
|
export type { EventConfig, EventDeclaration } from './events/event.js';
|
|
21
|
-
export type { ContextOf, EventWhere, WhereEventOptions, EventContexts, EventName, EventOptions, MessageEventOptions, ReactionEventOptions, } from './events/registry.js';
|
|
21
|
+
export type { ContextOf, EventWhere, WhereEventOptions, EventContexts, EventName, EventOptions, MessageEventOptions, ReactionEventOptions, AddedReaction, ClearedReactions, DeletedInvite, DeletedMessage, PollVote, PresenceChange, ScheduledEventInterest, Typing, UserReaction, VoiceActivity, VoiceChange, VoiceMove, } from './events/registry.js';
|
|
22
22
|
export type { CategoryChannel, Channel, DMChannel, FetchMessagesOptions, ForumChannel, ForumPostOptions, ForumTag, GuildChannel, GuildChannelEditOptions, InviteCreateOptions, PermissionOverwrite, TextBasedChannel, GuildTextBasedChannel, TextChannel, ThreadChannel, ThreadCreateOptions, ThreadEditOptions, ThreadMember, VoiceChannel, } from './structures/channel.js';
|
|
23
23
|
export type { GuildEmoji } from './structures/emoji.js';
|
|
24
24
|
export type { AuditLog, AuditLogEntry, AutoModerationRule, Ban, ChannelCreateOptions, Guild, GuildEditOptions, RoleCreateOptions, ScheduledEvent, Sticker, VoiceState, } from './structures/guild.js';
|
|
@@ -30,7 +30,9 @@ export type { CommandsTranslations, FrameworkTexts, LanguageConfig, LanguageDecl
|
|
|
30
30
|
export { presence } from './presence/presence.js';
|
|
31
31
|
export type { Activity, ActivityKind, PlainActivity, PresenceConfig, PresenceDeclaration, PresenceStatusName, StreamingActivity, } from './presence/presence.js';
|
|
32
32
|
export { store } from './store/store.js';
|
|
33
|
-
export type { ScopedStore, Store, StoreConfig, StoreEntry, StoreKey, StoreScope, StoreSetOptions, } from './store/store.js';
|
|
33
|
+
export type { ScopedStore, Store, StoreConfig, StoreEntry, StoreKey, StoreScope, StoreSetOptions, StoreStorage, } from './store/store.js';
|
|
34
|
+
export { ranking } from './ranking/ranking.js';
|
|
35
|
+
export type { Ranking, RankingConfig, RankingEntry, RankingOrder, ScopedRanking, } from './ranking/ranking.js';
|
|
34
36
|
export { task } from './tasks/task.js';
|
|
35
37
|
export type { CronTaskConfig, EveryTaskConfig, TaskConfig, TaskContext, TaskDeclaration, } from './tasks/task.js';
|
|
36
38
|
export type { AssetFile, AssetOptions } from './assets/asset.js';
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ export { event } from './events/event.js';
|
|
|
22
22
|
export { language } from './messages/messages.js';
|
|
23
23
|
export { presence } from './presence/presence.js';
|
|
24
24
|
export { store } from './store/store.js';
|
|
25
|
+
export { ranking } from './ranking/ranking.js';
|
|
25
26
|
export { task } from './tasks/task.js';
|
|
26
27
|
// Errors handlers can catch.
|
|
27
28
|
export { DiscordApiError, DiscordUnavailableError, InvalidTokenError, } from './rest/errors.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Declaration } from '../loader/loader.js';
|
|
2
|
+
import { type StoreStorage } from '../store/backend.js';
|
|
3
|
+
import type { StoreScope } from '../store/store.js';
|
|
4
|
+
import { type RankingOrder } from './ranking.js';
|
|
5
|
+
/** A ranking, checked: what the project keeps of it. */
|
|
6
|
+
export interface LoadedRanking {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly scope: StoreScope;
|
|
9
|
+
readonly storage: StoreStorage;
|
|
10
|
+
readonly order: RankingOrder;
|
|
11
|
+
}
|
|
12
|
+
export declare const rankingDeclaration: Declaration<LoadedRanking>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// What a file declares with `ranking()`, checked when it loads, so a wrong
|
|
2
|
+
// scope, storage or order is explained before any score is kept; the
|
|
3
|
+
// ranking is then bound to the name of its export.
|
|
4
|
+
import { STORAGES } from '../store/backend.js';
|
|
5
|
+
import { bindRanking, isRankingDeclaration, rankingStateOf, } from './ranking.js';
|
|
6
|
+
const fail = (message) => {
|
|
7
|
+
throw new TypeError(message);
|
|
8
|
+
};
|
|
9
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10
|
+
const KEYS = ['scope', 'storage', 'order'];
|
|
11
|
+
const SCOPES = ['guild', 'global'];
|
|
12
|
+
const ORDERS = ['highest', 'lowest'];
|
|
13
|
+
/** A name can name a file in `data/`, like a store's. */
|
|
14
|
+
const NAME = /^[\w.-]+$/;
|
|
15
|
+
export const rankingDeclaration = {
|
|
16
|
+
one: 'ranking',
|
|
17
|
+
many: 'rankings',
|
|
18
|
+
is: isRankingDeclaration,
|
|
19
|
+
list: false,
|
|
20
|
+
read(value, { name }) {
|
|
21
|
+
const config = rankingStateOf(value)?.config;
|
|
22
|
+
if (!isRecord(config)) {
|
|
23
|
+
return fail("ranking() takes an object, or nothing: ranking({ order: 'lowest' }).");
|
|
24
|
+
}
|
|
25
|
+
for (const key of Object.keys(config)) {
|
|
26
|
+
if (!KEYS.includes(key)) {
|
|
27
|
+
fail(`"${key}" is not something a ranking has. It can have: ${KEYS.join(', ')}.`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (!NAME.test(name)) {
|
|
31
|
+
fail(`"${name}" can't name a ranking: the name of the export is the name of the ranking and of its file in data/, made of letters, digits, _ . and -.`);
|
|
32
|
+
}
|
|
33
|
+
const scope = (config.scope ?? 'guild');
|
|
34
|
+
if (!SCOPES.includes(scope)) {
|
|
35
|
+
fail(`"scope" is 'guild' (a ranking per server, the default) or 'global' (one ranking for the whole bot), got ${JSON.stringify(config.scope)}.`);
|
|
36
|
+
}
|
|
37
|
+
const storage = (config.storage ?? 'file');
|
|
38
|
+
if (!STORAGES.includes(storage)) {
|
|
39
|
+
fail(`"storage" is 'file' (a file in data/, the default) or 'redis' (the Redis of REDIS_URL in .env), got ${JSON.stringify(config.storage)}.`);
|
|
40
|
+
}
|
|
41
|
+
const order = (config.order ?? 'highest');
|
|
42
|
+
if (!ORDERS.includes(order)) {
|
|
43
|
+
fail(`"order" is 'highest' (the highest score first, the default) or 'lowest' (the lowest first), got ${JSON.stringify(config.order)}.`);
|
|
44
|
+
}
|
|
45
|
+
bindRanking(value, { name, scope, storage, order });
|
|
46
|
+
return Object.freeze({ name, scope, storage, order });
|
|
47
|
+
},
|
|
48
|
+
};
|