@dereekb/discord 14.0.0 → 14.1.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.
@@ -1,8 +1,8 @@
1
- import { GatewayIntentBits, Client, Events, TextChannel, InteractionType } from 'discord.js';
1
+ import { GatewayIntentBits, Client, Events, Routes, TextChannel, InteractionType } from 'discord.js';
2
2
  import { Injectable, Inject, Logger, Module, Post, Req, Controller } from '@nestjs/common';
3
3
  import { isTestNodeEnv, RawBody } from '@dereekb/nestjs';
4
4
  import { ConfigService, ConfigModule } from '@nestjs/config';
5
- import { discordOAuthFactory, exchangeAuthorizationCode, refreshAccessToken, readCurrentUser, discordOAuthAuthorizeUrlFactory, discordAccessTokenFromTokenResponse } from '@dereekb/discord';
5
+ import { discordOAuthFactory, exchangeAuthorizationCode, refreshAccessToken, readCurrentUser, revokeToken, discordOAuthAuthorizeUrlFactory, discordAccessTokenFromTokenResponse } from '@dereekb/discord';
6
6
  import { handlerFactory, handlerConfigurerFactory, handlerMappedSetFunctionFactory, isHexWithByteLength } from '@dereekb/util';
7
7
  import { createPublicKey, verify } from 'node:crypto';
8
8
 
@@ -42,7 +42,7 @@ function _create_class$6(Constructor, protoProps, staticProps) {
42
42
  if (staticProps) _defineProperties$6(Constructor, staticProps);
43
43
  return Constructor;
44
44
  }
45
- function _define_property$7(obj, key, value) {
45
+ function _define_property$8(obj, key, value) {
46
46
  if (key in obj) {
47
47
  Object.defineProperty(obj, key, {
48
48
  value: value,
@@ -92,7 +92,7 @@ function _define_property$7(obj, key, value) {
92
92
  */ var DiscordServiceConfig = /*#__PURE__*/ function() {
93
93
  function DiscordServiceConfig() {
94
94
  _class_call_check$8(this, DiscordServiceConfig);
95
- _define_property$7(this, "discord", void 0);
95
+ _define_property$8(this, "discord", void 0);
96
96
  }
97
97
  _create_class$6(DiscordServiceConfig, null, [
98
98
  {
@@ -150,7 +150,7 @@ function _create_class$5(Constructor, protoProps, staticProps) {
150
150
  if (protoProps) _defineProperties$5(Constructor.prototype, protoProps);
151
151
  return Constructor;
152
152
  }
153
- function _define_property$6(obj, key, value) {
153
+ function _define_property$7(obj, key, value) {
154
154
  if (key in obj) {
155
155
  Object.defineProperty(obj, key, {
156
156
  value: value,
@@ -167,7 +167,7 @@ function _instanceof(left, right) {
167
167
  return !!right[Symbol.hasInstance](left);
168
168
  } else return left instanceof right;
169
169
  }
170
- function _object_spread$2(target) {
170
+ function _object_spread$3(target) {
171
171
  for(var i = 1; i < arguments.length; i++){
172
172
  var source = arguments[i] != null ? arguments[i] : {};
173
173
  var ownKeys = Object.keys(source);
@@ -177,7 +177,7 @@ function _object_spread$2(target) {
177
177
  }));
178
178
  }
179
179
  ownKeys.forEach(function(key) {
180
- _define_property$6(target, key, source[key]);
180
+ _define_property$7(target, key, source[key]);
181
181
  });
182
182
  }
183
183
  return target;
@@ -289,16 +289,22 @@ function _ts_generator$4(thisArg, body) {
289
289
  */ var DiscordApi = /*#__PURE__*/ function() {
290
290
  function DiscordApi(config) {
291
291
  _class_call_check$7(this, DiscordApi);
292
- _define_property$6(this, "config", void 0);
293
- _define_property$6(this, "logger", new Logger('DiscordApi'));
292
+ _define_property$7(this, "config", void 0);
293
+ _define_property$7(this, "logger", new Logger('DiscordApi'));
294
294
  /**
295
295
  * The underlying discord.js Client instance.
296
- */ _define_property$6(this, "client", void 0);
296
+ */ _define_property$7(this, "client", void 0);
297
297
  this.config = config;
298
- var clientOptions = config.discord.clientOptions;
299
- this.client = new Client(_object_spread$2({
298
+ var _config_discord = config.discord, botToken = _config_discord.botToken, clientOptions = _config_discord.clientOptions;
299
+ this.client = new Client(_object_spread$3({
300
300
  intents: DEFAULT_DISCORD_INTENTS
301
301
  }, clientOptions));
302
+ // login() is the only other thing that sets the REST token, so without this the REST client is
303
+ // unusable when autoLogin is false. Setting it here is what lets a consumer use the REST API
304
+ // (fetchChannelMessages, for instance) without opening a gateway websocket.
305
+ if (isUsableDiscordBotToken(botToken)) {
306
+ this.client.rest.setToken(botToken);
307
+ }
302
308
  }
303
309
  _create_class$5(DiscordApi, [
304
310
  {
@@ -416,6 +422,64 @@ function _ts_generator$4(thisArg, body) {
416
422
  return _this.client.off(Events.MessageCreate, handler);
417
423
  };
418
424
  }
425
+ },
426
+ {
427
+ key: "fetchChannelMessages",
428
+ value: /**
429
+ * Fetches a page of a channel's message history.
430
+ *
431
+ * Goes through the REST client rather than `client.channels.fetch(...).messages.fetch(...)` for
432
+ * three reasons: it needs no gateway session (only a token), `@discordjs/rest` already applies
433
+ * Discord's per-route bucket rate limiting and 429 retries, and the returned `APIMessage` is plain
434
+ * JSON rather than a discord.js `Message` carrying a live client back-reference.
435
+ *
436
+ * Pair with `discordScanMessagesFactory` from `@dereekb/discord` to walk a channel's history.
437
+ *
438
+ * @param input - The channel to read and the pagination filter to read it with.
439
+ * @returns The page of messages, newest-first.
440
+ *
441
+ * @example
442
+ * ```ts
443
+ * const page = await discordApi.fetchChannelMessages({ channelId, limit: 50 });
444
+ * ```
445
+ */ function fetchChannelMessages(input) {
446
+ return _async_to_generator$4(function() {
447
+ var channelId, before, after, around, limit, query, data;
448
+ return _ts_generator$4(this, function(_state) {
449
+ switch(_state.label){
450
+ case 0:
451
+ channelId = input.channelId, before = input.before, after = input.after, around = input.around, limit = input.limit;
452
+ query = new URLSearchParams();
453
+ if (before) {
454
+ query.set('before', before);
455
+ }
456
+ if (after) {
457
+ query.set('after', after);
458
+ }
459
+ if (around) {
460
+ query.set('around', around);
461
+ }
462
+ if (limit != null) {
463
+ query.set('limit', String(limit));
464
+ }
465
+ return [
466
+ 4,
467
+ this.client.rest.get(Routes.channelMessages(channelId), {
468
+ query: query
469
+ })
470
+ ];
471
+ case 1:
472
+ data = _state.sent();
473
+ return [
474
+ 2,
475
+ {
476
+ data: data
477
+ }
478
+ ];
479
+ }
480
+ });
481
+ }).call(this);
482
+ }
419
483
  }
420
484
  ]);
421
485
  return DiscordApi;
@@ -425,9 +489,36 @@ DiscordApi = __decorate([
425
489
  __param(0, Inject(DiscordServiceConfig))
426
490
  ], DiscordApi);
427
491
 
492
+ function _array_like_to_array$2(arr, len) {
493
+ if (len == null || len > arr.length) len = arr.length;
494
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
495
+ return arr2;
496
+ }
497
+ function _array_without_holes$2(arr) {
498
+ if (Array.isArray(arr)) return _array_like_to_array$2(arr);
499
+ }
428
500
  function _class_call_check$6(instance, Constructor) {
429
501
  if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
430
502
  }
503
+ function _iterable_to_array$2(iter) {
504
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
505
+ return Array.from(iter);
506
+ }
507
+ }
508
+ function _non_iterable_spread$2() {
509
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
510
+ }
511
+ function _to_consumable_array$2(arr) {
512
+ return _array_without_holes$2(arr) || _iterable_to_array$2(arr) || _unsupported_iterable_to_array$2(arr) || _non_iterable_spread$2();
513
+ }
514
+ function _unsupported_iterable_to_array$2(o, minLen) {
515
+ if (!o) return;
516
+ if (typeof o === "string") return _array_like_to_array$2(o, minLen);
517
+ var n = Object.prototype.toString.call(o).slice(8, -1);
518
+ if (n === "Object" && o.constructor) n = o.constructor.name;
519
+ if (n === "Map" || n === "Set") return Array.from(n);
520
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$2(o, minLen);
521
+ }
431
522
  /**
432
523
  * Factory that creates a DiscordServiceConfig from environment variables.
433
524
  *
@@ -475,6 +566,36 @@ DiscordModule = __decorate([
475
566
  ]
476
567
  })
477
568
  ], DiscordModule);
569
+ /**
570
+ * Convenience function used to generate ModuleMetadata for an app's DiscordModule.
571
+ *
572
+ * Mirrors `appDiscordOAuthModuleMetadata`, letting an app supply its own config factory
573
+ * instead of re-declaring the whole provider.
574
+ *
575
+ * @param config - The module metadata configuration including an optional config factory.
576
+ * @returns NestJS ModuleMetadata for registering the DiscordModule.
577
+ */ function appDiscordModuleMetadata(config) {
578
+ var _config_discordServiceConfigFactory;
579
+ var imports = config.imports, exports = config.exports, providers = config.providers;
580
+ return {
581
+ imports: [
582
+ ConfigModule
583
+ ].concat(_to_consumable_array$2(imports !== null && imports !== void 0 ? imports : [])),
584
+ exports: [
585
+ DiscordApi
586
+ ].concat(_to_consumable_array$2(exports !== null && exports !== void 0 ? exports : [])),
587
+ providers: [
588
+ {
589
+ provide: DiscordServiceConfig,
590
+ inject: [
591
+ ConfigService
592
+ ],
593
+ useFactory: (_config_discordServiceConfigFactory = config.discordServiceConfigFactory) !== null && _config_discordServiceConfigFactory !== void 0 ? _config_discordServiceConfigFactory : discordServiceConfigFactory
594
+ },
595
+ DiscordApi
596
+ ].concat(_to_consumable_array$2(providers !== null && providers !== void 0 ? providers : []))
597
+ };
598
+ }
478
599
 
479
600
  function _array_like_to_array$1(arr, len) {
480
601
  if (len == null || len > arr.length) len = arr.length;
@@ -484,6 +605,17 @@ function _array_like_to_array$1(arr, len) {
484
605
  function _array_without_holes$1(arr) {
485
606
  if (Array.isArray(arr)) return _array_like_to_array$1(arr);
486
607
  }
608
+ function _define_property$6(obj, key, value) {
609
+ if (key in obj) {
610
+ Object.defineProperty(obj, key, {
611
+ value: value,
612
+ enumerable: true,
613
+ configurable: true,
614
+ writable: true
615
+ });
616
+ } else obj[key] = value;
617
+ return obj;
618
+ }
487
619
  function _iterable_to_array$1(iter) {
488
620
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
489
621
  return Array.from(iter);
@@ -492,6 +624,39 @@ function _iterable_to_array$1(iter) {
492
624
  function _non_iterable_spread$1() {
493
625
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
494
626
  }
627
+ function _object_spread$2(target) {
628
+ for(var i = 1; i < arguments.length; i++){
629
+ var source = arguments[i] != null ? arguments[i] : {};
630
+ var ownKeys = Object.keys(source);
631
+ if (typeof Object.getOwnPropertySymbols === "function") {
632
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
633
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
634
+ }));
635
+ }
636
+ ownKeys.forEach(function(key) {
637
+ _define_property$6(target, key, source[key]);
638
+ });
639
+ }
640
+ return target;
641
+ }
642
+ function ownKeys$2(object, enumerableOnly) {
643
+ var keys = Object.keys(object);
644
+ if (Object.getOwnPropertySymbols) {
645
+ var symbols = Object.getOwnPropertySymbols(object);
646
+ keys.push.apply(keys, symbols);
647
+ }
648
+ return keys;
649
+ }
650
+ function _object_spread_props$2(target, source) {
651
+ source = source != null ? source : {};
652
+ if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
653
+ else {
654
+ ownKeys$2(Object(source)).forEach(function(key) {
655
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
656
+ });
657
+ }
658
+ return target;
659
+ }
495
660
  function _to_consumable_array$1(arr) {
496
661
  return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$1(arr) || _non_iterable_spread$1();
497
662
  }
@@ -536,6 +701,32 @@ function _unsupported_iterable_to_array$1(o, minLen) {
536
701
  intents: _to_consumable_array$1(DEFAULT_DISCORD_INTENTS).concat(_to_consumable_array$1(additionalIntents))
537
702
  };
538
703
  }
704
+ /**
705
+ * Creates a {@link DiscordFetchMessagePageFetchFunction} bound to a single channel.
706
+ *
707
+ * This is the bridge between the `DiscordApi` REST client and the fetch-only scanning/pagination
708
+ * utilities in `@dereekb/discord`, which take an injected fetch function and know nothing about
709
+ * discord.js or a bot token.
710
+ *
711
+ * @param discordApi - The api to fetch messages through.
712
+ * @param channelId - The channel to read messages from.
713
+ * @returns A fetch function that pages through that channel's messages.
714
+ *
715
+ * @example
716
+ * ```ts
717
+ * const scan = discordScanMessagesFactory({
718
+ * fetch: discordApiChannelMessagesFetchFunction(discordApi, channelId)
719
+ * });
720
+ *
721
+ * await scan({ baseInput: {}, afterMessageId, handleMessages });
722
+ * ```
723
+ */ function discordApiChannelMessagesFetchFunction(discordApi, channelId) {
724
+ return function(input) {
725
+ return discordApi.fetchChannelMessages(_object_spread_props$2(_object_spread$2({}, input), {
726
+ channelId: channelId
727
+ }));
728
+ };
729
+ }
539
730
 
540
731
  function _class_call_check$5(instance, Constructor) {
541
732
  if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
@@ -900,6 +1091,19 @@ function _ts_generator$3(thisArg, body) {
900
1091
  return readCurrentUser(this.oauthContext);
901
1092
  }
902
1093
  },
1094
+ {
1095
+ key: "revokeToken",
1096
+ get: /**
1097
+ * Configured pass-through for {@link revokeToken}.
1098
+ *
1099
+ * Ends Discord's side of the authorization. Deleting the stored credentials alone leaves the grant
1100
+ * live at Discord, so a token captured before the disconnect stays usable.
1101
+ *
1102
+ * @returns Function to revoke an access or refresh token.
1103
+ */ function get() {
1104
+ return revokeToken(this.oauthContext);
1105
+ }
1106
+ },
903
1107
  {
904
1108
  /**
905
1109
  * Builds a {@link DiscordOAuthAuthorizeUrlFactory} for the app's client id.
@@ -1853,4 +2057,4 @@ DiscordWebhookModule = __decorate([
1853
2057
  })
1854
2058
  ], DiscordWebhookModule);
1855
2059
 
1856
- export { DEFAULT_DISCORD_INTENTS, DISCORD_BOT_TOKEN_ENV_VAR, DISCORD_BOT_TOKEN_PLACEHOLDER, DISCORD_CLIENT_ID_CONFIG_KEY, DISCORD_CLIENT_SECRET_CONFIG_KEY, DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH, DISCORD_PUBLIC_KEY_ENV_VAR, DISCORD_SERVICE_NAME, DiscordApi, DiscordModule, DiscordOAuthApi, DiscordOAuthServiceConfig, DiscordServiceConfig, DiscordWebhookController, DiscordWebhookModule, DiscordWebhookService, DiscordWebhookServiceConfig, appDiscordOAuthModuleMetadata, discordClientOptionsWithIntents, discordDefaultClientOptions, discordInteractionHandlerConfigurerFactory, discordInteractionHandlerFactory, discordOAuthServiceConfigFactory, discordServiceConfigFactory, discordWebhookEventVerifier, discordWebhookInteraction, discordWebhookServiceConfigFactory, isUsableDiscordBotToken };
2060
+ export { DEFAULT_DISCORD_INTENTS, DISCORD_BOT_TOKEN_ENV_VAR, DISCORD_BOT_TOKEN_PLACEHOLDER, DISCORD_CLIENT_ID_CONFIG_KEY, DISCORD_CLIENT_SECRET_CONFIG_KEY, DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH, DISCORD_PUBLIC_KEY_ENV_VAR, DISCORD_SERVICE_NAME, DiscordApi, DiscordModule, DiscordOAuthApi, DiscordOAuthServiceConfig, DiscordServiceConfig, DiscordWebhookController, DiscordWebhookModule, DiscordWebhookService, DiscordWebhookServiceConfig, appDiscordModuleMetadata, appDiscordOAuthModuleMetadata, discordApiChannelMessagesFetchFunction, discordClientOptionsWithIntents, discordDefaultClientOptions, discordInteractionHandlerConfigurerFactory, discordInteractionHandlerFactory, discordOAuthServiceConfigFactory, discordServiceConfigFactory, discordWebhookEventVerifier, discordWebhookInteraction, discordWebhookServiceConfigFactory, isUsableDiscordBotToken };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dereekb/discord/nestjs",
3
- "version": "14.0.0",
3
+ "version": "14.1.0",
4
4
  "type": "module",
5
5
  "peerDependencies": {
6
- "@dereekb/discord": "14.0.0",
7
- "@dereekb/nestjs": "14.0.0",
8
- "@dereekb/rxjs": "14.0.0",
9
- "@dereekb/util": "14.0.0",
6
+ "@dereekb/discord": "14.1.0",
7
+ "@dereekb/nestjs": "14.1.0",
8
+ "@dereekb/rxjs": "14.1.0",
9
+ "@dereekb/util": "14.1.0",
10
10
  "@nestjs/common": "^12.0.1",
11
11
  "@nestjs/config": "^12.0.0",
12
12
  "discord.js": "^14.26.3",
@@ -1,7 +1,18 @@
1
- import { Client, type Message } from 'discord.js';
1
+ import { type APIMessage, Client, type Message } from 'discord.js';
2
2
  import { type OnModuleDestroy, type OnModuleInit } from '@nestjs/common';
3
3
  import { DiscordServiceConfig } from './discord.config';
4
- import { type DiscordChannelId } from '@dereekb/discord';
4
+ import { type DiscordChannelId, type DiscordMessagePageFilter, type DiscordMessagePageResult } from '@dereekb/discord';
5
+ /**
6
+ * Input for {@link DiscordApi.fetchChannelMessages}.
7
+ *
8
+ * Extends the shared pagination filter with the channel to read from.
9
+ */
10
+ export interface DiscordFetchChannelMessagesInput extends DiscordMessagePageFilter {
11
+ /**
12
+ * The channel to read messages from.
13
+ */
14
+ readonly channelId: DiscordChannelId;
15
+ }
5
16
  /**
6
17
  * Injectable service that wraps the discord.js Client for bot operations.
7
18
  *
@@ -66,4 +77,23 @@ export declare class DiscordApi implements OnModuleInit, OnModuleDestroy {
66
77
  * @returns An unsubscribe function that removes the registered handler.
67
78
  */
68
79
  onMessage(handler: (message: Message) => void): () => void;
80
+ /**
81
+ * Fetches a page of a channel's message history.
82
+ *
83
+ * Goes through the REST client rather than `client.channels.fetch(...).messages.fetch(...)` for
84
+ * three reasons: it needs no gateway session (only a token), `@discordjs/rest` already applies
85
+ * Discord's per-route bucket rate limiting and 429 retries, and the returned `APIMessage` is plain
86
+ * JSON rather than a discord.js `Message` carrying a live client back-reference.
87
+ *
88
+ * Pair with `discordScanMessagesFactory` from `@dereekb/discord` to walk a channel's history.
89
+ *
90
+ * @param input - The channel to read and the pagination filter to read it with.
91
+ * @returns The page of messages, newest-first.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const page = await discordApi.fetchChannelMessages({ channelId, limit: 50 });
96
+ * ```
97
+ */
98
+ fetchChannelMessages(input: DiscordFetchChannelMessagesInput): Promise<DiscordMessagePageResult<APIMessage>>;
69
99
  }
@@ -1,3 +1,4 @@
1
+ import { type ModuleMetadata } from '@nestjs/common';
1
2
  import { ConfigService } from '@nestjs/config';
2
3
  import { DiscordServiceConfig } from './discord.config';
3
4
  /**
@@ -18,3 +19,28 @@ export declare function discordServiceConfigFactory(configService: ConfigService
18
19
  */
19
20
  export declare class DiscordModule {
20
21
  }
22
+ /**
23
+ * Factory that creates a {@link DiscordServiceConfig} from the app's config service.
24
+ */
25
+ export type DiscordServiceConfigFactory = (configService: ConfigService) => DiscordServiceConfig;
26
+ export interface ProvideAppDiscordMetadataConfig extends Pick<ModuleMetadata, 'imports' | 'exports' | 'providers'> {
27
+ /**
28
+ * Optional override for the DiscordServiceConfigFactory.
29
+ *
30
+ * An app that only uses the REST api should supply a factory with `autoLogin: false`, so a cold
31
+ * start never opens a gateway websocket it will not use.
32
+ *
33
+ * @default discordServiceConfigFactory
34
+ */
35
+ readonly discordServiceConfigFactory?: DiscordServiceConfigFactory;
36
+ }
37
+ /**
38
+ * Convenience function used to generate ModuleMetadata for an app's DiscordModule.
39
+ *
40
+ * Mirrors `appDiscordOAuthModuleMetadata`, letting an app supply its own config factory
41
+ * instead of re-declaring the whole provider.
42
+ *
43
+ * @param config - The module metadata configuration including an optional config factory.
44
+ * @returns NestJS ModuleMetadata for registering the DiscordModule.
45
+ */
46
+ export declare function appDiscordModuleMetadata(config: ProvideAppDiscordMetadataConfig): ModuleMetadata;
@@ -1,4 +1,6 @@
1
- import { type GatewayIntentBits, type ClientOptions } from 'discord.js';
1
+ import { type APIMessage, type GatewayIntentBits, type ClientOptions } from 'discord.js';
2
+ import { type DiscordApi } from './discord.api';
3
+ import { type DiscordChannelId, type DiscordFetchMessagePageFetchFunction, type DiscordMessagePageFilter } from '@dereekb/discord';
2
4
  /**
3
5
  * Returns default ClientOptions for a bot that reads guild messages.
4
6
  *
@@ -26,3 +28,24 @@ export declare function discordDefaultClientOptions(): Partial<ClientOptions>;
26
28
  * ```
27
29
  */
28
30
  export declare function discordClientOptionsWithIntents(additionalIntents: GatewayIntentBits[]): Partial<ClientOptions>;
31
+ /**
32
+ * Creates a {@link DiscordFetchMessagePageFetchFunction} bound to a single channel.
33
+ *
34
+ * This is the bridge between the `DiscordApi` REST client and the fetch-only scanning/pagination
35
+ * utilities in `@dereekb/discord`, which take an injected fetch function and know nothing about
36
+ * discord.js or a bot token.
37
+ *
38
+ * @param discordApi - The api to fetch messages through.
39
+ * @param channelId - The channel to read messages from.
40
+ * @returns A fetch function that pages through that channel's messages.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const scan = discordScanMessagesFactory({
45
+ * fetch: discordApiChannelMessagesFetchFunction(discordApi, channelId)
46
+ * });
47
+ *
48
+ * await scan({ baseInput: {}, afterMessageId, handleMessages });
49
+ * ```
50
+ */
51
+ export declare function discordApiChannelMessagesFetchFunction(discordApi: DiscordApi, channelId: DiscordChannelId): DiscordFetchMessagePageFetchFunction<DiscordMessagePageFilter, APIMessage>;
@@ -43,6 +43,15 @@ export declare class DiscordOAuthApi {
43
43
  * @returns Function to read the Discord user an access token belongs to.
44
44
  */
45
45
  get readCurrentUser(): (input: import("@dereekb/discord").DiscordOAuthReadCurrentUserInput) => Promise<import("@dereekb/discord").DiscordOAuthCurrentUser>;
46
+ /**
47
+ * Configured pass-through for {@link revokeToken}.
48
+ *
49
+ * Ends Discord's side of the authorization. Deleting the stored credentials alone leaves the grant
50
+ * live at Discord, so a token captured before the disconnect stays usable.
51
+ *
52
+ * @returns Function to revoke an access or refresh token.
53
+ */
54
+ get revokeToken(): (input: import("@dereekb/discord").DiscordOAuthRevokeTokenInput) => Promise<void>;
46
55
  /**
47
56
  * Builds a {@link DiscordOAuthAuthorizeUrlFactory} for the app's client id.
48
57
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/discord",
3
- "version": "14.0.0",
3
+ "version": "14.1.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "exports": {
@@ -17,9 +17,9 @@
17
17
  }
18
18
  },
19
19
  "peerDependencies": {
20
- "@dereekb/nestjs": "14.0.0",
21
- "@dereekb/rxjs": "14.0.0",
22
- "@dereekb/util": "14.0.0",
20
+ "@dereekb/nestjs": "14.1.0",
21
+ "@dereekb/rxjs": "14.1.0",
22
+ "@dereekb/util": "14.1.0",
23
23
  "@nestjs/common": "^12.0.1",
24
24
  "@nestjs/config": "^12.0.0",
25
25
  "discord.js": "^14.26.3",