@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.
- package/index.esm.js +713 -47
- package/nestjs/index.esm.js +217 -13
- package/nestjs/package.json +5 -5
- package/nestjs/src/lib/discord/discord.api.d.ts +32 -2
- package/nestjs/src/lib/discord/discord.module.d.ts +26 -0
- package/nestjs/src/lib/discord/discord.util.d.ts +24 -1
- package/nestjs/src/lib/oauth/oauth.api.d.ts +9 -0
- package/package.json +4 -4
- package/src/lib/discord.api.scan.d.ts +257 -0
- package/src/lib/discord.snowflake.d.ts +70 -0
- package/src/lib/discord.type.d.ts +4 -0
- package/src/lib/index.d.ts +2 -0
- package/src/lib/oauth/oauth.api.d.ts +62 -12
- package/src/lib/oauth/oauth.authorize.d.ts +23 -4
- package/src/lib/oauth/oauth.config.d.ts +17 -1
package/nestjs/index.esm.js
CHANGED
|
@@ -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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
293
|
-
_define_property$
|
|
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$
|
|
296
|
+
*/ _define_property$7(this, "client", void 0);
|
|
297
297
|
this.config = config;
|
|
298
|
-
var
|
|
299
|
-
this.client = new Client(_object_spread$
|
|
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 };
|
package/nestjs/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/discord/nestjs",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@dereekb/discord": "14.
|
|
7
|
-
"@dereekb/nestjs": "14.
|
|
8
|
-
"@dereekb/rxjs": "14.
|
|
9
|
-
"@dereekb/util": "14.
|
|
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.
|
|
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.
|
|
21
|
-
"@dereekb/rxjs": "14.
|
|
22
|
-
"@dereekb/util": "14.
|
|
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",
|