chapterjs 0.3.0 → 0.5.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.
Files changed (115) hide show
  1. package/README.md +5 -3
  2. package/dist/assets/public.js +4 -4
  3. package/dist/cli/build.d.ts +6 -2
  4. package/dist/cli/build.js +17 -4
  5. package/dist/cli/dev.js +37 -6
  6. package/dist/cli/env.d.ts +5 -0
  7. package/dist/cli/env.js +39 -3
  8. package/dist/cli/project.d.ts +61 -9
  9. package/dist/cli/project.js +250 -44
  10. package/dist/cli/redis.d.ts +23 -0
  11. package/dist/cli/redis.js +69 -0
  12. package/dist/cli/start.js +54 -18
  13. package/dist/cli/test.js +112 -18
  14. package/dist/commands/command.d.ts +140 -5
  15. package/dist/commands/command.js +17 -2
  16. package/dist/commands/declaration.d.ts +17 -4
  17. package/dist/commands/declaration.js +128 -2
  18. package/dist/commands/router.js +78 -18
  19. package/dist/commands/tree.d.ts +25 -4
  20. package/dist/commands/tree.js +95 -26
  21. package/dist/commands/twins.d.ts +8 -0
  22. package/dist/commands/twins.js +24 -6
  23. package/dist/components/button.d.ts +8 -3
  24. package/dist/components/declaration.d.ts +2 -2
  25. package/dist/components/declaration.js +16 -12
  26. package/dist/components/render.js +5 -0
  27. package/dist/components/router.js +41 -0
  28. package/dist/components/select.d.ts +12 -5
  29. package/dist/core/bot.d.ts +7 -0
  30. package/dist/core/bot.js +44 -0
  31. package/dist/discord/api.d.ts +2 -0
  32. package/dist/discord/api.js +2 -0
  33. package/dist/discord/permissions.d.ts +4 -4
  34. package/dist/discord/permissions.js +13 -0
  35. package/dist/events/registry.d.ts +265 -243
  36. package/dist/events/registry.js +131 -100
  37. package/dist/index.d.ts +7 -4
  38. package/dist/index.js +2 -1
  39. package/dist/interactions/dispatch.js +4 -2
  40. package/dist/loader/loader.d.ts +16 -0
  41. package/dist/loader/loader.js +52 -7
  42. package/dist/loader/usage.d.ts +15 -0
  43. package/dist/loader/usage.js +40 -0
  44. package/dist/loader/watch.d.ts +5 -3
  45. package/dist/loader/watch.js +88 -17
  46. package/dist/messages/commands.js +3 -0
  47. package/dist/messages/messages.d.ts +1 -0
  48. package/dist/messages/translate.js +5 -1
  49. package/dist/presence/declaration.d.ts +49 -2
  50. package/dist/presence/declaration.js +122 -39
  51. package/dist/presence/presence.d.ts +65 -6
  52. package/dist/presence/presence.js +11 -0
  53. package/dist/presence/rotation.d.ts +32 -0
  54. package/dist/presence/rotation.js +167 -0
  55. package/dist/ranking/declaration.d.ts +12 -0
  56. package/dist/ranking/declaration.js +48 -0
  57. package/dist/ranking/ranking.d.ts +102 -0
  58. package/dist/ranking/ranking.js +129 -0
  59. package/dist/redis/client.d.ts +36 -0
  60. package/dist/redis/client.js +252 -0
  61. package/dist/redis/protocol.d.ts +22 -0
  62. package/dist/redis/protocol.js +99 -0
  63. package/dist/redis/url.d.ts +24 -0
  64. package/dist/redis/url.js +50 -0
  65. package/dist/rest/errors.d.ts +0 -1
  66. package/dist/rest/errors.js +15 -1
  67. package/dist/rest/rest.js +10 -1
  68. package/dist/store/backend.d.ts +49 -4
  69. package/dist/store/backend.js +66 -11
  70. package/dist/store/declaration.d.ts +3 -0
  71. package/dist/store/declaration.js +8 -3
  72. package/dist/store/file-backend.d.ts +3 -2
  73. package/dist/store/file-backend.js +47 -1
  74. package/dist/store/ipc-backend.d.ts +24 -1
  75. package/dist/store/ipc-backend.js +49 -0
  76. package/dist/store/memory-backend.d.ts +4 -2
  77. package/dist/store/memory-backend.js +27 -1
  78. package/dist/store/ranking-backend.d.ts +45 -0
  79. package/dist/store/ranking-backend.js +82 -0
  80. package/dist/store/redis-backend.d.ts +38 -0
  81. package/dist/store/redis-backend.js +245 -0
  82. package/dist/store/redis-ranking.d.ts +15 -0
  83. package/dist/store/redis-ranking.js +69 -0
  84. package/dist/store/scope.d.ts +17 -1
  85. package/dist/store/scope.js +32 -3
  86. package/dist/store/store.d.ts +39 -5
  87. package/dist/store/store.js +79 -32
  88. package/dist/structures/channel.d.ts +13 -0
  89. package/dist/structures/channel.js +24 -0
  90. package/dist/structures/context.d.ts +3 -0
  91. package/dist/structures/entities.js +1 -0
  92. package/dist/structures/interaction.d.ts +6 -0
  93. package/dist/structures/interaction.js +20 -0
  94. package/dist/structures/invite.d.ts +6 -0
  95. package/dist/structures/invite.js +11 -0
  96. package/dist/structures/message.d.ts +17 -0
  97. package/dist/structures/message.js +33 -0
  98. package/dist/structures/wait.d.ts +105 -0
  99. package/dist/structures/wait.js +85 -0
  100. package/dist/testing/harness.d.ts +48 -8
  101. package/dist/testing/harness.js +156 -36
  102. package/dist/testing/index.d.ts +1 -1
  103. package/dist/testing/smoke.js +112 -1
  104. package/dist/testing/world.js +51 -2
  105. package/dist/util/call-site.d.ts +4 -0
  106. package/dist/util/call-site.js +22 -0
  107. package/dist/voice/connection.d.ts +2 -0
  108. package/dist/voice/connection.js +15 -1
  109. package/dist/voice/usage.d.ts +3 -2
  110. package/dist/voice/usage.js +7 -19
  111. package/dist/waiting/usage.d.ts +5 -0
  112. package/dist/waiting/usage.js +19 -0
  113. package/dist/waiting/waiters.d.ts +48 -0
  114. package/dist/waiting/waiters.js +107 -0
  115. package/package.json +1 -1
@@ -15,14 +15,22 @@ const ofGuild = ({ guild }) => guild;
15
15
  const channel = (on) => ({
16
16
  on,
17
17
  build: (ctx, data) => {
18
+ // A server's channel only: what the types promise.
18
19
  const found = ctx.cache.channels.get(data.id);
19
- return found ? { channel: found } : null;
20
+ return found?.isGuildChannel() || found?.isThread()
21
+ ? { channel: found, guild: found.guild }
22
+ : null;
20
23
  },
21
24
  });
22
25
  const deletedChannel = (on) => ({
23
26
  on,
24
27
  before: (ctx, data) => ctx.cache.channels.get(data.id) ?? null,
25
- build: (_ctx, _data, { before }) => before ? { channel: before } : null,
28
+ build: (_ctx, _data, { before }) => {
29
+ const channel = before;
30
+ return channel?.isGuildChannel() || channel?.isThread()
31
+ ? { channel, guild: channel.guild }
32
+ : null;
33
+ },
26
34
  });
27
35
  /**
28
36
  * Discord refused what an event needs before it can be given to its files:
@@ -95,14 +103,19 @@ const placeAndUser = (ctx, data, userId) => {
95
103
  };
96
104
  /** Who did it: what `prepare` got, or else what the bot knows. */
97
105
  const userFrom = (ctx, prepared, id) => prepared ?? ctx.cache.users.get(id) ?? null;
98
- /** Where something happened in a server or in private, as the bot knows it. */
106
+ /**
107
+ * Where something happened in a server or in private, as the bot knows
108
+ * it: `at` goes in the object of the event, `guild` next to it.
109
+ */
99
110
  const placeOf = (ctx, data) => {
100
111
  const found = ctx.cache.channels.get(data.channel_id);
101
112
  const guildId = data.guild_id ?? found?.guildId ?? null;
102
113
  return {
103
- channelId: data.channel_id,
104
- channel: found?.isTextBased() ? found : null,
105
- guildId,
114
+ at: {
115
+ channelId: data.channel_id,
116
+ channel: found?.isTextBased() ? found : null,
117
+ guildId,
118
+ },
106
119
  guild: guildId ? (ctx.cache.guilds.get(guildId) ?? null) : null,
107
120
  };
108
121
  };
@@ -114,15 +127,15 @@ const rememberedMember = (guild, userId) => guild?.members.get(userId) ?? null;
114
127
  * Whether a file wants something that happened in a server or in private:
115
128
  * it listens there, and in a server what it is promised is there.
116
129
  */
117
- const wantedPlace = (context, where, needsMember = false) => {
118
- const inGuild = context.guildId !== null;
130
+ const wantedPlace = (about, guild, where, needsMember = false) => {
131
+ const inGuild = about.guildId !== null;
119
132
  if (!listensThere(where, inGuild))
120
133
  return false;
121
134
  if (!inGuild)
122
135
  return true;
123
- return (context.guild !== null &&
124
- context.channel !== null &&
125
- (!needsMember || context.member != null));
136
+ return (guild !== null &&
137
+ about.channel !== null &&
138
+ (!needsMember || about.member != null));
126
139
  };
127
140
  /**
128
141
  * Private messages, bots and webhooks only reach the files that asked for
@@ -152,9 +165,10 @@ const wantedMessage = ({ message }, options) => {
152
165
  const message = (on) => ({
153
166
  on,
154
167
  prepare: channelOf,
155
- build: (ctx, data) => ({
156
- message: ctx.entities.message(data, data.guild_id),
157
- }),
168
+ build: (ctx, data) => {
169
+ const message = ctx.entities.message(data, data.guild_id);
170
+ return { message, guild: message.guild };
171
+ },
158
172
  });
159
173
  const member = (on) => ({
160
174
  on,
@@ -226,12 +240,15 @@ const cleared = (on) => ({
226
240
  on,
227
241
  prepare: channelOf,
228
242
  build: (ctx, data) => {
229
- const place = placeOf(ctx, data);
243
+ const { at, guild } = placeOf(ctx, data);
230
244
  return {
231
- emoji: 'emoji' in data ? toCamelCase(data.emoji) : null,
232
- messageId: data.message_id,
233
- message: rememberedMessage(place.channel, data.message_id),
234
- ...place,
245
+ reactions: {
246
+ emoji: 'emoji' in data ? toCamelCase(data.emoji) : null,
247
+ messageId: data.message_id,
248
+ message: rememberedMessage(at.channel, data.message_id),
249
+ ...at,
250
+ },
251
+ guild,
235
252
  };
236
253
  },
237
254
  });
@@ -239,17 +256,20 @@ const vote = (on) => ({
239
256
  on,
240
257
  prepare: (ctx, data) => placeAndUser(ctx, data, data.user_id),
241
258
  build: (ctx, data, { prepared }) => {
242
- const place = placeOf(ctx, data);
259
+ const { at, guild } = placeOf(ctx, data);
243
260
  const user = userFrom(ctx, prepared, data.user_id);
244
261
  if (!user)
245
262
  return null;
246
263
  return {
247
- answerId: data.answer_id,
248
- user,
249
- member: rememberedMember(place.guild, data.user_id),
250
- messageId: data.message_id,
251
- message: rememberedMessage(place.channel, data.message_id),
252
- ...place,
264
+ vote: {
265
+ answerId: data.answer_id,
266
+ user,
267
+ member: rememberedMember(guild, data.user_id),
268
+ messageId: data.message_id,
269
+ message: rememberedMessage(at.channel, data.message_id),
270
+ ...at,
271
+ },
272
+ guild,
253
273
  };
254
274
  },
255
275
  });
@@ -283,7 +303,7 @@ const voice = (pick) => ({
283
303
  : guild.members.get(data.user_id);
284
304
  if (!picked || !member)
285
305
  return null;
286
- return { ...picked, member, guild };
306
+ return { voice: { ...picked, member }, guild };
287
307
  },
288
308
  });
289
309
  const scheduled = (on) => ({
@@ -308,9 +328,11 @@ const interested = (on) => ({
308
328
  if (!guild || !user)
309
329
  return null;
310
330
  return {
311
- scheduledEventId: data.guild_scheduled_event_id,
312
- user,
313
- member: rememberedMember(guild, data.user_id),
331
+ interest: {
332
+ scheduledEventId: data.guild_scheduled_event_id,
333
+ user,
334
+ member: rememberedMember(guild, data.user_id),
335
+ },
314
336
  guild,
315
337
  };
316
338
  },
@@ -322,7 +344,7 @@ const interested = (on) => ({
322
344
  export const EVENTS = {
323
345
  ready: { intents: 0, sources: [] },
324
346
  messageCreate: {
325
- guildOf: ({ message }) => message.guild,
347
+ guildOf: ofGuild,
326
348
  // Without Message Content, the messages of others come empty.
327
349
  intents: ({ where }) => messagesIn(where) | I.MessageContent,
328
350
  options: { bots: 'boolean', where: PLACES },
@@ -330,7 +352,7 @@ export const EVENTS = {
330
352
  sources: [message('MESSAGE_CREATE')],
331
353
  },
332
354
  messageUpdate: {
333
- guildOf: ({ message }) => message.guild,
355
+ guildOf: ofGuild,
334
356
  intents: ({ where }) => messagesIn(where) | I.MessageContent,
335
357
  options: { bots: 'boolean', where: PLACES },
336
358
  accepts: wantedMessage,
@@ -340,9 +362,7 @@ export const EVENTS = {
340
362
  guildOf: ofGuild,
341
363
  intents: ({ where }) => messagesIn(where),
342
364
  options: { where: PLACES },
343
- accepts: ({ guildId, guild, channel }, options) => listensThere(options.where, guildId !== null) &&
344
- // In a server, the server and the channel are promised.
345
- (guildId === null || (guild !== null && channel !== null)),
365
+ accepts: ({ message, guild }, options) => wantedPlace(message, guild, options.where),
346
366
  sources: [
347
367
  {
348
368
  on: 'MESSAGE_DELETE',
@@ -353,11 +373,13 @@ export const EVENTS = {
353
373
  ? (found.messages.get(data.id) ?? null)
354
374
  : null;
355
375
  },
356
- build: (ctx, data, { before }) => ({
357
- messageId: data.id,
358
- ...placeOf(ctx, data),
359
- message: before,
360
- }),
376
+ build: (ctx, data, { before }) => {
377
+ const { at, guild } = placeOf(ctx, data);
378
+ return {
379
+ message: { id: data.id, ...at, before: before },
380
+ guild,
381
+ };
382
+ },
361
383
  },
362
384
  {
363
385
  // Messages deleted together: one occurrence each.
@@ -368,12 +390,11 @@ export const EVENTS = {
368
390
  return data.ids.map(id => found?.isTextBased() ? (found.messages.get(id) ?? null) : null);
369
391
  },
370
392
  build: (ctx, data, { before }) => {
371
- const place = placeOf(ctx, data);
393
+ const { at, guild } = placeOf(ctx, data);
372
394
  const messages = before;
373
- return data.ids.map((messageId, index) => ({
374
- messageId,
375
- ...place,
376
- message: messages[index] ?? null,
395
+ return data.ids.map((id, index) => ({
396
+ message: { id, ...at, before: messages[index] ?? null },
397
+ guild,
377
398
  }));
378
399
  },
379
400
  },
@@ -392,21 +413,14 @@ export const EVENTS = {
392
413
  memberLeave: {
393
414
  guildOf: ofGuild,
394
415
  intents: I.GuildMembers,
395
- // "The member as it was" is a member the bot remembered.
396
- remembers: { members: 1000 },
397
416
  sources: [
398
417
  {
399
418
  on: 'GUILD_MEMBER_REMOVE',
400
- before: (ctx, data) => findGuild(ctx, data.guild_id)?.members.get(data.user.id) ?? null,
401
- build: (ctx, data, { before }) => {
419
+ build: (ctx, data) => {
402
420
  const guild = findGuild(ctx, data.guild_id);
403
421
  if (!guild)
404
422
  return null;
405
- return {
406
- user: ctx.entities.user(data.user),
407
- guild,
408
- member: before,
409
- };
423
+ return { user: ctx.entities.user(data.user), guild };
410
424
  },
411
425
  },
412
426
  ],
@@ -437,17 +451,17 @@ export const EVENTS = {
437
451
  ],
438
452
  },
439
453
  channelCreate: {
440
- guildOf: ({ channel }) => channel.guild,
454
+ guildOf: ofGuild,
441
455
  intents: I.Guilds,
442
456
  sources: [channel('CHANNEL_CREATE'), channel('THREAD_CREATE')],
443
457
  },
444
458
  channelUpdate: {
445
- guildOf: ({ channel }) => channel.guild,
459
+ guildOf: ofGuild,
446
460
  intents: I.Guilds,
447
461
  sources: [channel('CHANNEL_UPDATE'), channel('THREAD_UPDATE')],
448
462
  },
449
463
  channelDelete: {
450
- guildOf: ({ channel }) => channel.guild,
464
+ guildOf: ofGuild,
451
465
  intents: I.Guilds,
452
466
  sources: [
453
467
  deletedChannel('CHANNEL_DELETE'),
@@ -476,7 +490,7 @@ export const EVENTS = {
476
490
  // Every role of a server is known: one that is not never was.
477
491
  if (!guild || !before)
478
492
  return null;
479
- return { roleId: data.role_id, guild, role: before };
493
+ return { role: before, guild };
480
494
  },
481
495
  },
482
496
  ],
@@ -544,7 +558,7 @@ export const EVENTS = {
544
558
  channel: { id: channelId },
545
559
  ...(inviter ? { inviter } : {}),
546
560
  });
547
- return { invite, ...place };
561
+ return { invite, guild: place.guild };
548
562
  },
549
563
  },
550
564
  ],
@@ -558,7 +572,12 @@ export const EVENTS = {
558
572
  prepare: channelOf,
559
573
  build: (ctx, data) => {
560
574
  const place = inviteChannel(ctx, data);
561
- return place ? { code: data.code, ...place } : null;
575
+ return place
576
+ ? {
577
+ invite: { code: data.code, channel: place.channel },
578
+ guild: place.guild,
579
+ }
580
+ : null;
562
581
  },
563
582
  },
564
583
  ],
@@ -583,15 +602,15 @@ export const EVENTS = {
583
602
  guildOf: ofGuild,
584
603
  intents: ({ where }) => reactionsIn(where),
585
604
  options: { bots: 'boolean', where: PLACES },
586
- accepts: (context, options) => wantedPlace(context, options.where, true) &&
587
- (options.bots === true || !context.user.bot),
605
+ accepts: ({ reaction, guild }, options) => wantedPlace(reaction, guild, options.where, true) &&
606
+ (options.bots === true || !reaction.user.bot),
588
607
  sources: [
589
608
  {
590
609
  on: 'MESSAGE_REACTION_ADD',
591
610
  // In a server, who reacted comes with the event.
592
611
  prepare: (ctx, data) => placeAndUser(ctx, data, data.member?.user ? null : data.user_id),
593
612
  build: (ctx, data, { prepared }) => {
594
- const place = placeOf(ctx, data);
613
+ const { at, guild } = placeOf(ctx, data);
595
614
  const member = data.member && data.guild_id
596
615
  ? ctx.entities.member(data.guild_id, data.member)
597
616
  : null;
@@ -599,14 +618,17 @@ export const EVENTS = {
599
618
  if (!user)
600
619
  return null;
601
620
  return {
602
- emoji: toCamelCase(data.emoji),
603
- user,
604
- member,
605
- burst: data.burst,
606
- messageId: data.message_id,
607
- message: rememberedMessage(place.channel, data.message_id),
608
- messageAuthorId: data.message_author_id ?? null,
609
- ...place,
621
+ reaction: {
622
+ emoji: toCamelCase(data.emoji),
623
+ user,
624
+ member,
625
+ burst: data.burst,
626
+ messageId: data.message_id,
627
+ message: rememberedMessage(at.channel, data.message_id),
628
+ messageAuthorId: data.message_author_id ?? null,
629
+ ...at,
630
+ },
631
+ guild,
610
632
  };
611
633
  },
612
634
  },
@@ -616,25 +638,28 @@ export const EVENTS = {
616
638
  guildOf: ofGuild,
617
639
  intents: ({ where }) => reactionsIn(where),
618
640
  options: { bots: 'boolean', where: PLACES },
619
- accepts: (context, options) => wantedPlace(context, options.where) &&
620
- (options.bots === true || !context.user.bot),
641
+ accepts: ({ reaction, guild }, options) => wantedPlace(reaction, guild, options.where) &&
642
+ (options.bots === true || !reaction.user.bot),
621
643
  sources: [
622
644
  {
623
645
  on: 'MESSAGE_REACTION_REMOVE',
624
646
  prepare: (ctx, data) => placeAndUser(ctx, data, data.user_id),
625
647
  build: (ctx, data, { prepared }) => {
626
- const place = placeOf(ctx, data);
648
+ const { at, guild } = placeOf(ctx, data);
627
649
  const user = userFrom(ctx, prepared, data.user_id);
628
650
  if (!user)
629
651
  return null;
630
652
  return {
631
- emoji: toCamelCase(data.emoji),
632
- user,
633
- member: rememberedMember(place.guild, data.user_id),
634
- burst: data.burst,
635
- messageId: data.message_id,
636
- message: rememberedMessage(place.channel, data.message_id),
637
- ...place,
653
+ reaction: {
654
+ emoji: toCamelCase(data.emoji),
655
+ user,
656
+ member: rememberedMember(guild, data.user_id),
657
+ burst: data.burst,
658
+ messageId: data.message_id,
659
+ message: rememberedMessage(at.channel, data.message_id),
660
+ ...at,
661
+ },
662
+ guild,
638
663
  };
639
664
  },
640
665
  },
@@ -644,7 +669,7 @@ export const EVENTS = {
644
669
  guildOf: ofGuild,
645
670
  intents: ({ where }) => reactionsIn(where),
646
671
  options: { where: PLACES },
647
- accepts: (context, options) => wantedPlace(context, options.where),
672
+ accepts: ({ reactions, guild }, options) => wantedPlace(reactions, guild, options.where),
648
673
  sources: [
649
674
  cleared('MESSAGE_REACTION_REMOVE_ALL'),
650
675
  cleared('MESSAGE_REACTION_REMOVE_EMOJI'),
@@ -654,14 +679,14 @@ export const EVENTS = {
654
679
  guildOf: ofGuild,
655
680
  intents: ({ where }) => pollsIn(where),
656
681
  options: { where: PLACES },
657
- accepts: (context, options) => wantedPlace(context, options.where),
682
+ accepts: ({ vote, guild }, options) => wantedPlace(vote, guild, options.where),
658
683
  sources: [vote('MESSAGE_POLL_VOTE_ADD')],
659
684
  },
660
685
  pollVoteRemove: {
661
686
  guildOf: ofGuild,
662
687
  intents: ({ where }) => pollsIn(where),
663
688
  options: { where: PLACES },
664
- accepts: (context, options) => wantedPlace(context, options.where),
689
+ accepts: ({ vote, guild }, options) => wantedPlace(vote, guild, options.where),
665
690
  sources: [vote('MESSAGE_POLL_VOTE_REMOVE')],
666
691
  },
667
692
  typingStart: {
@@ -669,7 +694,7 @@ export const EVENTS = {
669
694
  intents: ({ where }) => (where === 'dm' ? 0 : I.GuildMessageTyping) |
670
695
  (where === 'dm' || where === 'both' ? I.DirectMessageTyping : 0),
671
696
  options: { where: PLACES },
672
- accepts: (context, options) => wantedPlace(context, options.where, true),
697
+ accepts: ({ typing, guild }, options) => wantedPlace(typing, guild, options.where, true),
673
698
  sources: [
674
699
  {
675
700
  on: 'TYPING_START',
@@ -681,11 +706,15 @@ export const EVENTS = {
681
706
  const user = member?.user ?? userFrom(ctx, prepared, data.user_id);
682
707
  if (!user)
683
708
  return null;
709
+ const { at, guild } = placeOf(ctx, data);
684
710
  return {
685
- user,
686
- member,
687
- startedAt: new Date(data.timestamp * 1000),
688
- ...placeOf(ctx, data),
711
+ typing: {
712
+ user,
713
+ member,
714
+ startedAt: new Date(data.timestamp * 1000),
715
+ ...at,
716
+ },
717
+ guild,
689
718
  };
690
719
  },
691
720
  },
@@ -711,7 +740,7 @@ export const EVENTS = {
711
740
  if (!added.member?.user)
712
741
  continue;
713
742
  const member = ctx.entities.member(data.guild_id, added.member);
714
- joined.push({ member, user: member.user, ...place });
743
+ joined.push({ thread: place.thread, member, guild: place.guild });
715
744
  }
716
745
  return joined;
717
746
  },
@@ -732,10 +761,10 @@ export const EVENTS = {
732
761
  if (!place)
733
762
  return null;
734
763
  return (data.removed_member_ids ?? []).map(userId => ({
764
+ thread: place.thread,
735
765
  userId,
736
- user: ctx.cache.users.get(userId) ?? null,
737
766
  member: rememberedMember(place.guild, userId),
738
- ...place,
767
+ guild: place.guild,
739
768
  }));
740
769
  },
741
770
  },
@@ -745,14 +774,14 @@ export const EVENTS = {
745
774
  guildOf: ofGuild,
746
775
  intents: I.GuildVoiceStates,
747
776
  sources: [
748
- voice((was, now) => !was && now ? { channel: now.channel, voice: stateOf(now) } : null),
777
+ voice((was, now) => !was && now ? { channel: now.channel, state: stateOf(now) } : null),
749
778
  ],
750
779
  },
751
780
  voiceLeave: {
752
781
  guildOf: ofGuild,
753
782
  intents: I.GuildVoiceStates,
754
783
  sources: [
755
- voice((was, now) => was && !now ? { channel: was.channel, voice: stateOf(was) } : null),
784
+ voice((was, now) => was && !now ? { channel: was.channel, state: stateOf(was) } : null),
756
785
  ],
757
786
  },
758
787
  voiceMove: {
@@ -760,7 +789,7 @@ export const EVENTS = {
760
789
  intents: I.GuildVoiceStates,
761
790
  sources: [
762
791
  voice((was, now) => was && now && was.channel.id !== now.channel.id
763
- ? { from: was.channel, to: now.channel, voice: stateOf(now) }
792
+ ? { from: was.channel, to: now.channel, state: stateOf(now) }
764
793
  : null),
765
794
  ],
766
795
  },
@@ -774,7 +803,7 @@ export const EVENTS = {
774
803
  JSON.stringify(was.state) !== JSON.stringify(now.state)
775
804
  ? {
776
805
  channel: now.channel,
777
- voice: stateOf(now),
806
+ state: stateOf(now),
778
807
  before: stateOf(was),
779
808
  }
780
809
  : null),
@@ -797,10 +826,12 @@ export const EVENTS = {
797
826
  ? ctx.entities.user(raw)
798
827
  : (ctx.cache.users.get(raw.id) ?? null);
799
828
  return {
800
- userId: raw.id,
801
- user,
802
- member: rememberedMember(guild, raw.id),
803
- presence: toCamelCase(presence),
829
+ presence: {
830
+ ...toCamelCase(presence),
831
+ userId: raw.id,
832
+ user,
833
+ member: rememberedMember(guild, raw.id),
834
+ },
804
835
  guild,
805
836
  };
806
837
  },
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { command } from './commands/command.js';
2
- export type { AutocompleteContext, ChannelOption, CommandAutocomplete, CommandConfig, CommandContext, CommandInDm, CommandInGuild, CommandInPrivate, CommandWhere, CommandDeclaration, CommandLocales, CommandName, CommandOption, CommandOptions, CommandTranslation, Cooldown, Duration, NumberOption, OptionsSoFar, OptionTranslation, OptionValuesOf, SimpleOption, StringOption, Suggestion, } from './commands/command.js';
2
+ export type { AutocompleteContext, ChannelOption, CommandAutocomplete, CommandConfig, CommandContext, CommandInDm, CommandInGuild, CommandInPrivate, CommandWhere, CommandDeclaration, CommandLocales, CommandName, CommandOption, CommandOptions, CommandTranslation, Cooldown, MenuConfig, MenuContext, MenuDeclaration, MenuLocales, MenuTranslation, MenuType, Duration, NumberOption, OptionsSoFar, OptionTranslation, OptionValuesOf, SimpleOption, StringOption, Suggestion, } from './commands/command.js';
3
3
  export type { CommandInteraction, ComponentInteraction, DmCommandInteraction, GuildCommandInteraction, PrivateCommandInteraction, Interaction, InteractionReply, InteractionReplyOptions, ModalInteraction, } from './structures/interaction.js';
4
4
  export type { DynamicText, TextContext } from './components/component.js';
5
5
  export { button } from './components/button.js';
@@ -18,19 +18,22 @@ 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';
25
25
  export type { Invite } from './structures/invite.js';
26
26
  export type { BanOptions, GuildMember, MemberEditOptions, } from './structures/member.js';
27
27
  export type { Attachment, EmojiInput, DmMessage, GuildMessage, MemberMessage, Message, PrivateMessage, MessageFlagName, Reaction, ReactionEmoji, } from './structures/message.js';
28
+ export type { Click, CollectMessagesOptions, PersonInput, WaitedReaction, WaitForClickOptions, WaitForMessageOptions, WaitForReactionOptions, } from './structures/wait.js';
28
29
  export { language } from './messages/messages.js';
29
30
  export type { CommandsTranslations, FrameworkTexts, LanguageConfig, LanguageDeclaration, MergedMessages, MessagesOf, MessageText, MessageTexts, PluralText, ProjectCommands, ProjectLanguageDefaults, ParamsArgs, ParamsOf, Placeholders, ProjectLocale, ProjectLocales, LocaleGiven, ProjectMessages, TranslationContext, Translator, } from './messages/messages.js';
30
31
  export { presence } from './presence/presence.js';
31
- export type { Activity, ActivityKind, PlainActivity, PresenceConfig, PresenceDeclaration, PresenceStatusName, StreamingActivity, } from './presence/presence.js';
32
+ export type { Activities, Activity, ActivityKind, ActivityText, PlainActivity, PresenceConfig, PresenceContext, PresenceDeclaration, PresenceStatusName, RotatingPresenceConfig, SinglePresenceConfig, StreamingActivity, } from './presence/presence.js';
32
33
  export { store } from './store/store.js';
33
- export type { ScopedStore, Store, StoreConfig, StoreEntry, StoreKey, StoreScope, StoreSetOptions, } from './store/store.js';
34
+ export type { ScopedStore, Store, StoreConfig, StoreEntry, StoreKey, StoreScope, StoreSetOptions, StoreStorage, } from './store/store.js';
35
+ export { ranking } from './ranking/ranking.js';
36
+ export type { Ranking, RankingConfig, RankingEntry, RankingOrder, ScopedRanking, } from './ranking/ranking.js';
34
37
  export { task } from './tasks/task.js';
35
38
  export type { CronTaskConfig, EveryTaskConfig, TaskConfig, TaskContext, TaskDeclaration, } from './tasks/task.js';
36
39
  export type { AssetFile, AssetOptions } from './assets/asset.js';
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@
9
9
  // (in events, commands...) and never creates them: classes are exported as
10
10
  // types only, and nothing here lets user code connect to Discord or send
11
11
  // requests by itself.
12
- // Slash commands: what the files of src/commands/ are written with.
12
+ // Commands (slash and menu): what the files of src/commands/ are written with.
13
13
  export { command } from './commands/command.js';
14
14
  export { button } from './components/button.js';
15
15
  export { select } from './components/select.js';
@@ -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';
@@ -8,7 +8,7 @@ import { setTimeout as sleep } from 'node:timers/promises';
8
8
  import { phrase } from '../messages/phrases.js';
9
9
  import { DiscordApiError } from '../rest/errors.js';
10
10
  import { ctxOf } from '../structures/base.js';
11
- import { isUpdating } from '../structures/interaction.js';
11
+ import { answersSent, isUpdating, } from '../structures/interaction.js';
12
12
  /** Who did it, as Discord sent it: the member in a server, the user elsewhere. */
13
13
  export function authorOf(raw) {
14
14
  const user = raw.member?.user ?? raw.user;
@@ -87,7 +87,9 @@ export function runInteraction(options) {
87
87
  .then(() => options.defer())
88
88
  .catch(() => { });
89
89
  return new Promise(resolve => resolve(withGuild(options.guildId, options.run)))
90
- .then(() => {
90
+ .then(async () => {
91
+ // An answer asked without await is on its way: not a missing one.
92
+ await answersSent(interaction);
91
93
  if (!interaction.answered) {
92
94
  reporter.onWarning(file, `${name} ${options.unanswered}`);
93
95
  }
@@ -50,6 +50,22 @@ export declare const siteName: (site: {
50
50
  file: string;
51
51
  export?: string;
52
52
  }) => string;
53
+ /** What tells one export of the project from another: `src/a.ts#ban`. */
54
+ export declare const siteKey: (site: {
55
+ file: string;
56
+ export: string;
57
+ }) => string;
58
+ /**
59
+ * The order in which declarations that can't both be kept (two with one
60
+ * name) are read, the first one winning: what already ran first (`running`,
61
+ * the `siteKey`s of the declarations of the last load), so that a file saved
62
+ * in dev never takes its name from one that works, then by file and export,
63
+ * so that the choice never depends on the order the files were found in.
64
+ */
65
+ export declare function bySite<T extends {
66
+ file: string;
67
+ export: string;
68
+ }>(entries: readonly T[], running?: ReadonlySet<string>): T[];
53
69
  /** A file of the project, found but not run. */
54
70
  export interface FoundFile {
55
71
  /** The path from the project folder, with `/`: `src/ping.ts`. */