seyfert 0.1.0 → 1.0.1
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 +19 -30
- package/lib/api/CDN.d.ts +0 -8
- package/lib/api/CDN.js +7 -13
- package/lib/api/Router.d.ts +2 -2
- package/lib/api/Router.js +1 -1
- package/lib/api/Routes/applications.d.ts +1 -1
- package/lib/api/Routes/channels.d.ts +1 -1
- package/lib/api/Routes/gateway.d.ts +1 -1
- package/lib/api/Routes/guilds.d.ts +1 -1
- package/lib/api/Routes/interactions.d.ts +1 -1
- package/lib/api/Routes/invites.d.ts +1 -1
- package/lib/api/Routes/stage-instances.d.ts +1 -1
- package/lib/api/Routes/stickers.d.ts +1 -1
- package/lib/api/Routes/users.d.ts +1 -1
- package/lib/api/Routes/voice.d.ts +1 -1
- package/lib/api/Routes/webhooks.d.ts +1 -1
- package/lib/api/api.d.ts +44 -0
- package/lib/api/api.js +354 -0
- package/lib/api/bucket.d.ts +19 -0
- package/lib/api/bucket.js +71 -0
- package/lib/api/index.d.ts +1 -1
- package/lib/api/index.js +1 -1
- package/lib/api/shared.d.ts +33 -5
- package/lib/api/shared.js +2 -7
- package/lib/api/utils/constants.d.ts +1 -30
- package/lib/api/utils/constants.js +2 -41
- package/lib/api/utils/types.d.ts +1 -320
- package/lib/api/utils/utils.d.ts +0 -38
- package/lib/api/utils/utils.js +1 -139
- package/lib/builders/ActionRow.js +1 -1
- package/lib/builders/Attachment.d.ts +14 -6
- package/lib/builders/Attachment.js +30 -7
- package/lib/builders/Button.d.ts +5 -14
- package/lib/builders/Button.js +0 -11
- package/lib/builders/{MessageEmbed.d.ts → Embed.d.ts} +15 -15
- package/lib/builders/{MessageEmbed.js → Embed.js} +16 -16
- package/lib/builders/Modal.js +1 -1
- package/lib/builders/SelectMenu.d.ts +14 -15
- package/lib/builders/SelectMenu.js +19 -18
- package/lib/builders/index.d.ts +1 -1
- package/lib/builders/index.js +1 -1
- package/lib/builders/types.d.ts +2 -2
- package/lib/cache/adapters/default.d.ts +1 -0
- package/lib/cache/adapters/default.js +3 -2
- package/lib/cache/adapters/redis.d.ts +3 -3
- package/lib/cache/adapters/redis.js +14 -5
- package/lib/cache/adapters/types.d.ts +1 -0
- package/lib/cache/adapters/workeradapter.d.ts +10 -1
- package/lib/cache/adapters/workeradapter.js +8 -3
- package/lib/cache/index.d.ts +18 -5
- package/lib/cache/index.js +23 -9
- package/lib/cache/resources/channels.d.ts +6 -2
- package/lib/cache/resources/channels.js +12 -6
- package/lib/cache/resources/default/base.d.ts +17 -16
- package/lib/cache/resources/default/base.js +25 -24
- package/lib/cache/resources/default/guild-based.d.ts +22 -19
- package/lib/cache/resources/default/guild-based.js +32 -31
- package/lib/cache/resources/default/guild-related.d.ts +22 -19
- package/lib/cache/resources/default/guild-related.js +37 -43
- package/lib/cache/resources/emojis.d.ts +4 -2
- package/lib/cache/resources/emojis.js +8 -6
- package/lib/cache/resources/guilds.d.ts +4 -2
- package/lib/cache/resources/guilds.js +15 -8
- package/lib/cache/resources/members.d.ts +4 -2
- package/lib/cache/resources/members.js +16 -13
- package/lib/cache/resources/overwrites.d.ts +25 -0
- package/lib/cache/resources/overwrites.js +39 -0
- package/lib/cache/resources/presence.js +3 -4
- package/lib/cache/resources/roles.d.ts +4 -2
- package/lib/cache/resources/roles.js +8 -6
- package/lib/cache/resources/stickers.d.ts +4 -2
- package/lib/cache/resources/stickers.js +8 -6
- package/lib/cache/resources/threads.d.ts +4 -2
- package/lib/cache/resources/threads.js +8 -6
- package/lib/cache/resources/users.d.ts +4 -2
- package/lib/cache/resources/users.js +8 -6
- package/lib/cache/resources/voice-states.d.ts +3 -3
- package/lib/cache/resources/voice-states.js +6 -7
- package/lib/client/base.d.ts +48 -16
- package/lib/client/base.js +19 -15
- package/lib/client/client.d.ts +15 -4
- package/lib/client/client.js +26 -28
- package/lib/client/httpclient.d.ts +3 -5
- package/lib/client/httpclient.js +29 -16
- package/lib/client/{oninteraction.d.ts → oninteractioncreate.d.ts} +1 -1
- package/lib/client/{oninteraction.js → oninteractioncreate.js} +34 -23
- package/lib/client/onmessagecreate.d.ts +3 -0
- package/lib/client/onmessagecreate.js +337 -0
- package/lib/client/workerclient.d.ts +19 -2
- package/lib/client/workerclient.js +156 -46
- package/lib/collection.d.ts +1 -1
- package/lib/collection.js +9 -6
- package/lib/commands/applications/chat.d.ts +32 -25
- package/lib/commands/applications/chat.js +51 -34
- package/lib/commands/applications/chatcontext.d.ts +34 -16
- package/lib/commands/applications/chatcontext.js +99 -20
- package/lib/commands/applications/menu.d.ts +9 -8
- package/lib/commands/applications/menu.js +14 -5
- package/lib/commands/applications/menucontext.d.ts +27 -10
- package/lib/commands/applications/menucontext.js +51 -7
- package/lib/commands/applications/options.d.ts +13 -13
- package/lib/commands/applications/shared.d.ts +7 -2
- package/lib/commands/decorators.d.ts +14 -14
- package/lib/commands/decorators.js +9 -5
- package/lib/commands/handler.d.ts +2 -1
- package/lib/commands/handler.js +60 -14
- package/lib/commands/index.d.ts +1 -1
- package/lib/commands/index.js +2 -1
- package/lib/commands/optionresolver.d.ts +6 -5
- package/lib/commands/optionresolver.js +10 -6
- package/lib/common/bot/watcher.d.ts +3 -3
- package/lib/common/bot/watcher.js +3 -1
- package/lib/common/index.d.ts +1 -1
- package/lib/common/index.js +2 -1
- package/lib/common/it/logger.d.ts +11 -0
- package/lib/common/it/logger.js +51 -2
- package/lib/common/it/utils.d.ts +3 -13
- package/lib/common/it/utils.js +9 -30
- package/lib/common/shorters/channels.d.ts +55 -5
- package/lib/common/shorters/channels.js +59 -0
- package/lib/common/shorters/guilds.d.ts +5 -2
- package/lib/common/shorters/guilds.js +18 -0
- package/lib/common/shorters/messages.js +0 -2
- package/lib/common/shorters/overwrites.d.ts +29 -0
- package/lib/common/shorters/overwrites.js +63 -0
- package/lib/common/shorters/roles.js +3 -3
- package/lib/common/shorters/webhook.d.ts +2 -2
- package/lib/common/types/util.d.ts +3 -2
- package/lib/common/types/write.d.ts +3 -7
- package/lib/components/handler.d.ts +11 -17
- package/lib/components/handler.js +45 -93
- package/lib/components/index.d.ts +0 -1
- package/lib/components/index.js +0 -1
- package/lib/components/listener.d.ts +2 -2
- package/lib/components/listener.js +2 -3
- package/lib/events/event.d.ts +2 -2
- package/lib/events/handler.d.ts +3 -2
- package/lib/events/handler.js +14 -6
- package/lib/events/hooks/dispatch.d.ts +2 -1
- package/lib/events/hooks/dispatch.js +5 -1
- package/lib/events/hooks/thread.d.ts +63 -63
- package/lib/index.d.ts +8 -5
- package/lib/index.js +20 -10
- package/lib/langs/handler.d.ts +6 -4
- package/lib/langs/handler.js +10 -8
- package/lib/langs/router.d.ts +8 -9
- package/lib/langs/router.js +5 -5
- package/lib/structures/ClientUser.d.ts +1 -16
- package/lib/structures/ClientUser.js +0 -31
- package/lib/structures/Guild.d.ts +1 -1
- package/lib/structures/GuildMember.d.ts +12 -0
- package/lib/structures/GuildMember.js +14 -0
- package/lib/structures/GuildRole.d.ts +4 -2
- package/lib/structures/GuildRole.js +4 -1
- package/lib/structures/GuildTemplate.js +1 -1
- package/lib/structures/Interaction.d.ts +2 -0
- package/lib/structures/Interaction.js +12 -13
- package/lib/structures/Message.d.ts +7 -2
- package/lib/structures/Message.js +6 -3
- package/lib/structures/Sticker.d.ts +1 -1
- package/lib/structures/Sticker.js +1 -1
- package/lib/structures/User.d.ts +5 -0
- package/lib/structures/User.js +3 -0
- package/lib/structures/Webhook.d.ts +1 -1
- package/lib/structures/Webhook.js +1 -1
- package/lib/structures/channels.d.ts +45 -6
- package/lib/structures/channels.js +23 -7
- package/lib/structures/extra/BitField.d.ts +9 -6
- package/lib/structures/extra/BitField.js +27 -3
- package/lib/structures/extra/Permissions.d.ts +6 -1
- package/lib/structures/extra/Permissions.js +7 -0
- package/lib/websocket/constants/index.js +1 -3
- package/lib/websocket/discord/basesocket.js +0 -1
- package/lib/websocket/discord/shared.d.ts +2 -0
- package/lib/websocket/discord/worker.d.ts +23 -7
- package/lib/websocket/discord/workermanager.d.ts +32 -5
- package/lib/websocket/discord/workermanager.js +98 -29
- package/package.json +23 -21
- package/lib/api/REST.d.ts +0 -127
- package/lib/api/REST.js +0 -424
- package/lib/api/errors/DiscordAPIError.d.ts +0 -51
- package/lib/api/errors/DiscordAPIError.js +0 -81
- package/lib/api/errors/HTTPError.d.ts +0 -20
- package/lib/api/errors/HTTPError.js +0 -28
- package/lib/api/errors/RateLimitError.d.ts +0 -19
- package/lib/api/errors/RateLimitError.js +0 -37
- package/lib/api/handlers/BurstHandler.d.ts +0 -51
- package/lib/api/handlers/BurstHandler.js +0 -124
- package/lib/api/handlers/SequentialHandler.d.ts +0 -81
- package/lib/api/handlers/SequentialHandler.js +0 -365
- package/lib/api/handlers/Shared.d.ts +0 -14
- package/lib/api/handlers/Shared.js +0 -125
- package/lib/api/interfaces/Handler.d.ts +0 -21
- package/lib/api/interfaces/Handler.js +0 -2
- package/lib/websocket/discord/handlemessage.d.ts +0 -0
- package/lib/websocket/discord/handlemessage.js +0 -1
- package/lib/websocket/discord/memberUpdate.d.ts +0 -16
- package/lib/websocket/discord/memberUpdate.js +0 -47
package/README.md
CHANGED
|
@@ -2,29 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
# **Seyfert**
|
|
4
4
|
|
|
5
|
-
<img src="
|
|
5
|
+
<img src="./assets/icon.png" alt="seyfert" width="200px" />
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Discord.js and Sapphire are deprecated, use Seyfert instead**
|
|
8
8
|
|
|
9
|
-
[](https://github.com/tiramisulabs/seyfert/blob/main/LICENSE)
|
|
10
|
+
[](https://www.npmjs.com/package/seyfert)
|
|
11
|
+
[](https://discord.com/invite/XNw2RZFzaP)
|
|
12
12
|
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
> [!WARNING]
|
|
16
|
-
> This readme is work in progress!
|
|
17
|
-
|
|
18
15
|
# FAQ
|
|
19
16
|
## So, what is `seyfert`?
|
|
20
|
-
Seyfert is the ultimate Discord framework!
|
|
17
|
+
Seyfert is the ultimate Discord framework! We make easy to interact with the Discord API, big cache control, scalable code and a pretty dev experience.
|
|
21
18
|
|
|
22
19
|
## Why I should use it?
|
|
23
|
-
|
|
20
|
+
There is a lot of reasons to use Seyfert, but we cannot put them all in here so there is a few of them!
|
|
21
|
+
|
|
22
|
+
- **RAM Saver**
|
|
23
|
+
- **Latest features**
|
|
24
|
+
- **Dev experience**
|
|
25
|
+
- **24/6 support (Sunday is for going to church)**
|
|
26
|
+
- **Written from Scratch**
|
|
27
|
+
- **Type-safe**
|
|
28
|
+
- **And many more!!**
|
|
24
29
|
|
|
25
|
-
> more questions soon...
|
|
26
30
|
|
|
27
|
-
# User guide
|
|
28
31
|
## Installation
|
|
29
32
|
> [!NOTE]
|
|
30
33
|
> You **NEED** Node.js 18>= for this to work, also we recomended Node.js 20 LTS and Bun latest
|
|
@@ -34,24 +37,10 @@ pnpm add seyfert
|
|
|
34
37
|
|
|
35
38
|
> You may use your preferred package manager, for this example I am using PNPM since is more efficient.
|
|
36
39
|
|
|
37
|
-
## Basic bot example
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
import { Client } from 'seyfert';
|
|
41
|
-
|
|
42
|
-
const client = new Client();
|
|
43
|
-
|
|
44
|
-
(async () => {
|
|
45
|
-
await client.start();
|
|
46
|
-
await client.uploadCommands().catch(e => {
|
|
47
|
-
console.error(JSON.stringify(e, null, 2))
|
|
48
|
-
process.exit(1)
|
|
49
|
-
})
|
|
50
|
-
})();
|
|
51
|
-
```
|
|
52
|
-
|
|
53
40
|
# Useful links
|
|
54
41
|
|
|
55
|
-
- [GitHub Repository](https://github.com/
|
|
42
|
+
- [GitHub Repository](https://github.com/tiramisulabs/seyfert)
|
|
56
43
|
- [Discord server](https://discord.com/invite/XNw2RZFzaP)
|
|
57
|
-
- [npm - core](https://www.npmjs.com/package
|
|
44
|
+
- [npm - core](https://www.npmjs.com/package/seyfert)
|
|
45
|
+
- [Website](https://seyfert.dev)
|
|
46
|
+
- [Documentation](https://docs.seyfert.dev)
|
package/lib/api/CDN.d.ts
CHANGED
|
@@ -120,14 +120,6 @@ export declare class CDN {
|
|
|
120
120
|
* @param options - Optional options for the emoji
|
|
121
121
|
*/
|
|
122
122
|
emoji(emojiId: string, options?: Readonly<BaseImageURLOptions>): string;
|
|
123
|
-
/**
|
|
124
|
-
* Generates an emoji's URL for an emoji.
|
|
125
|
-
*
|
|
126
|
-
* @param emojiId - The emoji id
|
|
127
|
-
* @param extension - The extension of the emoji
|
|
128
|
-
* @deprecated This overload is deprecated. Pass an object containing the extension instead.
|
|
129
|
-
*/
|
|
130
|
-
emoji(emojiId: string, extension?: ImageExtension): string;
|
|
131
123
|
/**
|
|
132
124
|
* Generates a guild member avatar URL.
|
|
133
125
|
*
|
package/lib/api/CDN.js
CHANGED
|
@@ -4,8 +4,6 @@ exports.CDN = void 0;
|
|
|
4
4
|
/* eslint-disable jsdoc/check-param-names */
|
|
5
5
|
const index_js_1 = require("../common/index.js");
|
|
6
6
|
const constants_js_1 = require("./utils/constants.js");
|
|
7
|
-
const utils_js_1 = require("./utils/utils.js");
|
|
8
|
-
let deprecationEmittedForEmoji = false;
|
|
9
7
|
/**
|
|
10
8
|
* The CDN link builder
|
|
11
9
|
*/
|
|
@@ -95,18 +93,14 @@ class CDN {
|
|
|
95
93
|
discoverySplash(guildId, splashHash, options) {
|
|
96
94
|
return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);
|
|
97
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Generates an emoji's URL for an emoji.
|
|
98
|
+
*
|
|
99
|
+
* @param emojiId - The emoji id
|
|
100
|
+
* @param options - Optional options for the emoji
|
|
101
|
+
*/
|
|
98
102
|
emoji(emojiId, options) {
|
|
99
|
-
|
|
100
|
-
if (typeof options === 'string') {
|
|
101
|
-
if (!deprecationEmittedForEmoji) {
|
|
102
|
-
(0, utils_js_1.deprecationWarning)('Passing a string for the second parameter of CDN#emoji() is deprecated. Use an object instead.');
|
|
103
|
-
deprecationEmittedForEmoji = true;
|
|
104
|
-
}
|
|
105
|
-
resolvedOptions = { extension: options };
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
resolvedOptions = options;
|
|
109
|
-
}
|
|
103
|
+
const resolvedOptions = options;
|
|
110
104
|
return this.makeURL(`/emojis/${emojiId}`, resolvedOptions);
|
|
111
105
|
}
|
|
112
106
|
/**
|
package/lib/api/Router.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { APIRoutes,
|
|
1
|
+
import type { APIRoutes, ApiHandler, CDNRoute } from './index';
|
|
2
2
|
export declare enum ProxyRequestMethod {
|
|
3
3
|
Delete = "delete",
|
|
4
4
|
Get = "get",
|
|
@@ -9,7 +9,7 @@ export declare enum ProxyRequestMethod {
|
|
|
9
9
|
export declare class Router {
|
|
10
10
|
private rest;
|
|
11
11
|
noop: () => void;
|
|
12
|
-
constructor(rest:
|
|
12
|
+
constructor(rest: ApiHandler);
|
|
13
13
|
createProxy(route?: string[]): APIRoutes;
|
|
14
14
|
}
|
|
15
15
|
export declare const CDNRouter: {
|
package/lib/api/Router.js
CHANGED
|
@@ -23,7 +23,7 @@ class Router {
|
|
|
23
23
|
return new Proxy(this.noop, {
|
|
24
24
|
get: (_, key) => {
|
|
25
25
|
if (ArrRequestsMethods.includes(key)) {
|
|
26
|
-
return (...options) => this.rest
|
|
26
|
+
return (...options) => this.rest.request(key.toUpperCase(), `/${route.join('/')}`, ...options);
|
|
27
27
|
}
|
|
28
28
|
return this.createProxy([...route, key]);
|
|
29
29
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RESTGetAPIApplicationCommandResult, RESTGetAPIApplicationCommandsQuery, RESTGetAPIApplicationCommandsResult, RESTGetAPIApplicationGuildCommandResult, RESTGetAPIApplicationGuildCommandsQuery, RESTGetAPIApplicationGuildCommandsResult, RESTGetAPIApplicationRoleConnectionMetadataResult, RESTGetAPIGuildApplicationCommandsPermissionsResult, RESTPatchAPIApplicationCommandJSONBody, RESTPatchAPIApplicationCommandResult, RESTPatchAPIApplicationGuildCommandJSONBody, RESTPatchAPIApplicationGuildCommandResult, RESTPostAPIApplicationCommandsJSONBody, RESTPostAPIApplicationCommandsResult, RESTPostAPIApplicationGuildCommandsJSONBody, RESTPostAPIApplicationGuildCommandsResult, RESTPutAPIApplicationCommandPermissionsJSONBody, RESTPutAPIApplicationCommandsJSONBody, RESTPutAPIApplicationCommandsResult, RESTPutAPIApplicationGuildCommandsJSONBody, RESTPutAPIApplicationGuildCommandsResult, RESTPutAPIApplicationRoleConnectionMetadataJSONBody, RESTPutAPIApplicationRoleConnectionMetadataResult, RESTPutAPIGuildApplicationCommandsPermissionsResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface ApplicationRoutes {
|
|
5
5
|
applications: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RESTDeleteAPIChannelAllMessageReactionsResult, RESTDeleteAPIChannelMessageReactionResult, RESTDeleteAPIChannelMessageResult, RESTDeleteAPIChannelPermissionResult, RESTDeleteAPIChannelPinResult, RESTDeleteAPIChannelRecipientResult, RESTDeleteAPIChannelResult, RESTDeleteAPIChannelThreadMembersResult, RESTGetAPIChannelInvitesResult, RESTGetAPIChannelMessageReactionUsersQuery, RESTGetAPIChannelMessageReactionUsersResult, RESTGetAPIChannelMessageResult, RESTGetAPIChannelMessagesQuery, RESTGetAPIChannelMessagesResult, RESTGetAPIChannelPinsResult, RESTGetAPIChannelResult, RESTGetAPIChannelThreadMemberQuery, RESTGetAPIChannelThreadMemberResult, RESTGetAPIChannelThreadMembersQuery, RESTGetAPIChannelThreadMembersResult, RESTGetAPIChannelThreadsArchivedPrivateResult, RESTGetAPIChannelThreadsArchivedPublicResult, RESTGetAPIChannelThreadsArchivedQuery, RESTGetAPIChannelUsersThreadsArchivedResult, RESTGetAPIGuildWebhooksResult, RESTPatchAPIChannelJSONBody, RESTPatchAPIChannelMessageJSONBody, RESTPatchAPIChannelMessageResult, RESTPatchAPIChannelResult, RESTPostAPIChannelFollowersJSONBody, RESTPostAPIChannelFollowersResult, RESTPostAPIChannelInviteJSONBody, RESTPostAPIChannelInviteResult, RESTPostAPIChannelMessageCrosspostResult, RESTPostAPIChannelMessageJSONBody, RESTPostAPIChannelMessageResult, RESTPostAPIChannelMessagesBulkDeleteJSONBody, RESTPostAPIChannelMessagesBulkDeleteResult, RESTPostAPIChannelMessagesThreadsJSONBody, RESTPostAPIChannelMessagesThreadsResult, RESTPostAPIChannelThreadsJSONBody, RESTPostAPIChannelThreadsResult, RESTPostAPIChannelTypingResult, RESTPostAPIChannelWebhookJSONBody, RESTPostAPIChannelWebhookResult, RESTPostAPIGuildForumThreadsJSONBody, RESTPutAPIChannelMessageReactionResult, RESTPutAPIChannelPermissionJSONBody, RESTPutAPIChannelPermissionResult, RESTPutAPIChannelPinResult, RESTPutAPIChannelRecipientJSONBody, RESTPutAPIChannelRecipientResult, RESTPutAPIChannelThreadMembersResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface ChannelRoutes {
|
|
5
5
|
channels(id: string): {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RESTGetAPIGatewayBotResult, RESTGetAPIGatewayResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface GatewayRoutes {
|
|
5
5
|
gateway: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { APIThreadChannel, Identify, OmitInsert, RESTDeleteAPIAutoModerationRuleResult, RESTDeleteAPIGuildBanResult, RESTDeleteAPIGuildEmojiResult, RESTDeleteAPIGuildIntegrationResult, RESTDeleteAPIGuildMemberResult, RESTDeleteAPIGuildMemberRoleResult, RESTDeleteAPIGuildResult, RESTDeleteAPIGuildRoleResult, RESTDeleteAPIGuildScheduledEventResult, RESTDeleteAPIGuildStickerResult, RESTDeleteAPIGuildTemplateResult, RESTGetAPIAuditLogQuery, RESTGetAPIAuditLogResult, RESTGetAPIAutoModerationRuleResult, RESTGetAPIAutoModerationRulesResult, RESTGetAPIGuildBanResult, RESTGetAPIGuildBansQuery, RESTGetAPIGuildBansResult, RESTGetAPIGuildChannelsResult, RESTGetAPIGuildEmojiResult, RESTGetAPIGuildEmojisResult, RESTGetAPIGuildIntegrationsResult, RESTGetAPIGuildInvitesResult, RESTGetAPIGuildMemberResult, RESTGetAPIGuildMembersQuery, RESTGetAPIGuildMembersResult, RESTGetAPIGuildMembersSearchQuery, RESTGetAPIGuildMembersSearchResult, RESTGetAPIGuildPreviewResult, RESTGetAPIGuildPruneCountQuery, RESTGetAPIGuildPruneCountResult, RESTGetAPIGuildQuery, RESTGetAPIGuildResult, RESTGetAPIGuildRolesResult, RESTGetAPIGuildScheduledEventQuery, RESTGetAPIGuildScheduledEventResult, RESTGetAPIGuildScheduledEventUsersQuery, RESTGetAPIGuildScheduledEventUsersResult, RESTGetAPIGuildScheduledEventsQuery, RESTGetAPIGuildScheduledEventsResult, RESTGetAPIGuildStickerResult, RESTGetAPIGuildStickersResult, RESTGetAPIGuildTemplatesResult, RESTGetAPIGuildThreadsResult, RESTGetAPIGuildVanityUrlResult, RESTGetAPIGuildVoiceRegionsResult, RESTGetAPIGuildWebhooksResult, RESTGetAPIGuildWelcomeScreenResult, RESTGetAPIGuildWidgetImageQuery, RESTGetAPIGuildWidgetImageResult, RESTGetAPIGuildWidgetJSONResult, RESTGetAPIGuildWidgetSettingsResult, RESTGetAPITemplateResult, RESTPatchAPIAutoModerationRuleJSONBody, RESTPatchAPIAutoModerationRuleResult, RESTPatchAPICurrentGuildMemberJSONBody, RESTPatchAPIGuildChannelPositionsJSONBody, RESTPatchAPIGuildChannelPositionsResult, RESTPatchAPIGuildEmojiJSONBody, RESTPatchAPIGuildEmojiResult, RESTPatchAPIGuildJSONBody, RESTPatchAPIGuildMemberJSONBody, RESTPatchAPIGuildMemberResult, RESTPatchAPIGuildResult, RESTPatchAPIGuildRoleJSONBody, RESTPatchAPIGuildRolePositionsJSONBody, RESTPatchAPIGuildRolePositionsResult, RESTPatchAPIGuildRoleResult, RESTPatchAPIGuildScheduledEventJSONBody, RESTPatchAPIGuildScheduledEventResult, RESTPatchAPIGuildStickerJSONBody, RESTPatchAPIGuildStickerResult, RESTPatchAPIGuildTemplateJSONBody, RESTPatchAPIGuildTemplateResult, RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody, RESTPatchAPIGuildVoiceStateCurrentMemberResult, RESTPatchAPIGuildVoiceStateUserJSONBody, RESTPatchAPIGuildVoiceStateUserResult, RESTPatchAPIGuildWelcomeScreenJSONBody, RESTPatchAPIGuildWelcomeScreenResult, RESTPatchAPIGuildWidgetSettingsJSONBody, RESTPatchAPIGuildWidgetSettingsResult, RESTPostAPIAutoModerationRuleJSONBody, RESTPostAPIAutoModerationRuleResult, RESTPostAPIGuildChannelJSONBody, RESTPostAPIGuildChannelResult, RESTPostAPIGuildEmojiJSONBody, RESTPostAPIGuildEmojiResult, RESTPostAPIGuildPruneJSONBody, RESTPostAPIGuildPruneResult, RESTPostAPIGuildRoleJSONBody, RESTPostAPIGuildRoleResult, RESTPostAPIGuildScheduledEventJSONBody, RESTPostAPIGuildScheduledEventResult, RESTPostAPIGuildStickerFormDataBody, RESTPostAPIGuildStickerResult, RESTPostAPIGuildTemplatesJSONBody, RESTPostAPIGuildTemplatesResult, RESTPostAPIGuildsJSONBody, RESTPostAPIGuildsMFAJSONBody, RESTPostAPIGuildsMFAResult, RESTPostAPIGuildsResult, RESTPostAPITemplateCreateGuildJSONBody, RESTPostAPITemplateCreateGuildResult, RESTPutAPIGuildBanJSONBody, RESTPutAPIGuildBanResult, RESTPutAPIGuildMemberJSONBody, RESTPutAPIGuildMemberResult, RESTPutAPIGuildMemberRoleResult, RESTPutAPIGuildTemplateSyncResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../REST';
|
|
3
2
|
import type { ProxyRequestMethod } from '../Router';
|
|
3
|
+
import type { RestArguments } from '../api';
|
|
4
4
|
import type { RawFile } from '../shared';
|
|
5
5
|
export interface GuildRoutes {
|
|
6
6
|
guilds: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RESTPostAPIInteractionCallbackJSONBody } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface InteractionRoutes {
|
|
5
5
|
interactions: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RESTDeleteAPIInviteResult, RESTGetAPIInviteQuery, RESTGetAPIInviteResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface InviteRoutes {
|
|
5
5
|
invites(id: string): {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RESTDeleteAPIStageInstanceResult, RESTGetAPIStageInstanceResult, RESTPatchAPIStageInstanceJSONBody, RESTPatchAPIStageInstanceResult, RESTPostAPIStageInstanceJSONBody, RESTPostAPIStageInstanceResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface StageInstanceRoutes {
|
|
5
5
|
'stage-instances': {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RESTGetAPIStickerResult, RESTGetNitroStickerPacksResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface StickerRoutes {
|
|
5
5
|
stickers(id: string): {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { APIDMChannel, RESTDeleteAPIGuildResult, RESTGetAPICurrentUserApplicationRoleConnectionResult, RESTGetAPICurrentUserConnectionsResult, RESTGetAPICurrentUserGuildsQuery, RESTGetAPICurrentUserGuildsResult, RESTGetAPICurrentUserResult, RESTGetAPIUserResult, RESTGetCurrentUserGuildMemberResult, RESTPatchAPICurrentUserJSONBody, RESTPatchAPICurrentUserResult, RESTPostAPICurrentUserCreateDMChannelJSONBody, RESTPutAPICurrentUserApplicationRoleConnectionJSONBody, RESTPutAPICurrentUserApplicationRoleConnectionResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface UserRoutes {
|
|
5
5
|
users: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RESTDeleteAPIWebhookResult, RESTDeleteAPIWebhookWithTokenMessageResult, RESTDeleteAPIWebhookWithTokenResult, RESTGetAPIWebhookResult, RESTGetAPIWebhookWithTokenMessageResult, RESTGetAPIWebhookWithTokenResult, RESTPatchAPIWebhookJSONBody, RESTPatchAPIWebhookResult, RESTPatchAPIWebhookWithTokenJSONBody, RESTPatchAPIWebhookWithTokenMessageJSONBody, RESTPatchAPIWebhookWithTokenMessageResult, RESTPatchAPIWebhookWithTokenResult, RESTPostAPIWebhookWithTokenGitHubQuery, RESTPostAPIWebhookWithTokenGitHubResult, RESTPostAPIWebhookWithTokenGitHubWaitResult, RESTPostAPIWebhookWithTokenJSONBody, RESTPostAPIWebhookWithTokenQuery, RESTPostAPIWebhookWithTokenResult, RESTPostAPIWebhookWithTokenSlackQuery, RESTPostAPIWebhookWithTokenSlackResult, RESTPostAPIWebhookWithTokenSlackWaitResult, RESTPostAPIWebhookWithTokenWaitResult } from '../../common';
|
|
2
|
-
import type { RestArguments } from '../
|
|
2
|
+
import type { RestArguments } from '../api';
|
|
3
3
|
import type { ProxyRequestMethod } from '../Router';
|
|
4
4
|
export interface WebhookRoutes {
|
|
5
5
|
webhooks(id: string): {
|
package/lib/api/api.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Logger } from '../common';
|
|
2
|
+
import { CDN } from './CDN';
|
|
3
|
+
import type { ProxyRequestMethod } from './Router';
|
|
4
|
+
import { Bucket } from './bucket';
|
|
5
|
+
import { type ApiHandlerInternalOptions, type ApiHandlerOptions, type ApiRequestOptions, type HttpMethods, type RawFile, type RequestHeaders } from './shared';
|
|
6
|
+
export declare class ApiHandler {
|
|
7
|
+
#private;
|
|
8
|
+
options: ApiHandlerInternalOptions;
|
|
9
|
+
globalBlock: boolean;
|
|
10
|
+
ratelimits: Map<string, Bucket>;
|
|
11
|
+
readyQueue: (() => void)[];
|
|
12
|
+
cdn: CDN;
|
|
13
|
+
debugger?: Logger;
|
|
14
|
+
workerPromises?: Map<string, {
|
|
15
|
+
resolve: (value: any) => any;
|
|
16
|
+
reject: (error: any) => any;
|
|
17
|
+
}>;
|
|
18
|
+
constructor(options: ApiHandlerOptions);
|
|
19
|
+
globalUnblock(): void;
|
|
20
|
+
request<T = any>(method: HttpMethods, url: `/${string}`, { auth, ...request }?: ApiRequestOptions): Promise<T>;
|
|
21
|
+
parseError(response: Response, result: unknown): Error;
|
|
22
|
+
handle50X(method: HttpMethods, url: `/${string}`, request: ApiRequestOptions, next: () => void): Promise<any>;
|
|
23
|
+
handle429(route: string, method: HttpMethods, url: `/${string}`, request: ApiRequestOptions, response: Response, result: any, next: () => void, reject: (err: unknown) => void, now: number): Promise<any>;
|
|
24
|
+
clearResetInterval(route: string): void;
|
|
25
|
+
setResetBucket(route: string, resp: Response, now: number, headerNow: number): void;
|
|
26
|
+
setRatelimitsBucket(route: string, resp: Response): void;
|
|
27
|
+
parseRequest(options: {
|
|
28
|
+
url: string;
|
|
29
|
+
headers: RequestHeaders;
|
|
30
|
+
request: ApiRequestOptions;
|
|
31
|
+
}): {
|
|
32
|
+
data: string | FormData | undefined;
|
|
33
|
+
finalUrl: `/${string}`;
|
|
34
|
+
};
|
|
35
|
+
routefy(url: string, method: HttpMethods): `/${string}`;
|
|
36
|
+
}
|
|
37
|
+
export type RequestOptions = Pick<ApiRequestOptions, 'reason' | 'auth' | 'appendToFormData'>;
|
|
38
|
+
export type RequestObject<M extends ProxyRequestMethod, B = Record<string, any>, Q = Record<string, any>, F extends RawFile[] = RawFile[]> = {
|
|
39
|
+
query?: Q;
|
|
40
|
+
} & RequestOptions & (M extends `${ProxyRequestMethod.Get}` ? unknown : {
|
|
41
|
+
body?: B;
|
|
42
|
+
files?: F;
|
|
43
|
+
});
|
|
44
|
+
export type RestArguments<M extends ProxyRequestMethod, B = any, Q extends never | Record<string, any> = any, F extends RawFile[] = RawFile[]> = M extends ProxyRequestMethod.Get ? Q extends never ? RequestObject<M, never, B, never> : never : RequestObject<M, B, Q, F>;
|
package/lib/api/api.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ApiHandler = void 0;
|
|
4
|
+
const magic_bytes_js_1 = require("magic-bytes.js");
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const promises_1 = require("node:timers/promises");
|
|
7
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
8
|
+
const common_1 = require("../common");
|
|
9
|
+
const functions_1 = require("../structures/extra/functions");
|
|
10
|
+
const CDN_1 = require("./CDN");
|
|
11
|
+
const bucket_1 = require("./bucket");
|
|
12
|
+
const shared_1 = require("./shared");
|
|
13
|
+
const utils_1 = require("./utils/utils");
|
|
14
|
+
class ApiHandler {
|
|
15
|
+
options;
|
|
16
|
+
globalBlock = false;
|
|
17
|
+
ratelimits = new Map();
|
|
18
|
+
readyQueue = [];
|
|
19
|
+
cdn = new CDN_1.CDN();
|
|
20
|
+
debugger;
|
|
21
|
+
workerPromises;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.options = {
|
|
24
|
+
baseUrl: 'api/v10',
|
|
25
|
+
domain: 'https://discord.com',
|
|
26
|
+
...options,
|
|
27
|
+
userAgent: shared_1.DefaultUserAgent,
|
|
28
|
+
};
|
|
29
|
+
if (options.debug) {
|
|
30
|
+
this.debugger = new common_1.Logger({
|
|
31
|
+
name: '[API]',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (options.workerProxy && !node_worker_threads_1.parentPort)
|
|
35
|
+
throw new Error('Cannot use workerProxy without a parent.');
|
|
36
|
+
if (options.workerProxy)
|
|
37
|
+
this.workerPromises = new Map();
|
|
38
|
+
}
|
|
39
|
+
globalUnblock() {
|
|
40
|
+
this.globalBlock = false;
|
|
41
|
+
let cb;
|
|
42
|
+
while ((cb = this.readyQueue.shift())) {
|
|
43
|
+
cb();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
#randomUUID() {
|
|
47
|
+
const uuid = (0, node_crypto_1.randomUUID)();
|
|
48
|
+
if (this.workerPromises.has(uuid))
|
|
49
|
+
return this.#randomUUID();
|
|
50
|
+
return uuid;
|
|
51
|
+
}
|
|
52
|
+
async request(method, url, { auth = true, ...request } = {}) {
|
|
53
|
+
if (this.options.workerProxy) {
|
|
54
|
+
const nonce = this.#randomUUID();
|
|
55
|
+
node_worker_threads_1.parentPort.postMessage({
|
|
56
|
+
method,
|
|
57
|
+
url,
|
|
58
|
+
type: 'WORKER_API_REQUEST',
|
|
59
|
+
workerId: node_worker_threads_1.workerData.workerId,
|
|
60
|
+
nonce,
|
|
61
|
+
requestOptions: { auth, ...request },
|
|
62
|
+
}, request.files
|
|
63
|
+
?.filter(x => !['string', 'boolean', 'number'].includes(typeof x.data))
|
|
64
|
+
.map(x => x.data));
|
|
65
|
+
let resolve = (_value) => { };
|
|
66
|
+
let reject = () => { };
|
|
67
|
+
const promise = new Promise((res, rej) => {
|
|
68
|
+
resolve = res;
|
|
69
|
+
reject = rej;
|
|
70
|
+
});
|
|
71
|
+
this.workerPromises.set(nonce, { reject, resolve });
|
|
72
|
+
return promise;
|
|
73
|
+
}
|
|
74
|
+
const route = request.route || this.routefy(url, method);
|
|
75
|
+
let attempts = 0;
|
|
76
|
+
const callback = async (next, resolve, reject) => {
|
|
77
|
+
const headers = {
|
|
78
|
+
'User-Agent': this.options.userAgent,
|
|
79
|
+
};
|
|
80
|
+
const { data, finalUrl } = this.parseRequest({
|
|
81
|
+
url,
|
|
82
|
+
headers,
|
|
83
|
+
request: { ...request, auth },
|
|
84
|
+
});
|
|
85
|
+
let response;
|
|
86
|
+
try {
|
|
87
|
+
const url = `${this.options.domain}/${this.options.baseUrl}${finalUrl}`;
|
|
88
|
+
this.debugger?.debug(`Sending, Method: ${method} | Url: [${finalUrl}](${route}) | Auth: ${auth}`);
|
|
89
|
+
response = await fetch(url, {
|
|
90
|
+
method,
|
|
91
|
+
headers,
|
|
92
|
+
body: data,
|
|
93
|
+
});
|
|
94
|
+
this.debugger?.debug(`Received response: ${response.statusText}(${response.status})`);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
this.debugger?.debug('Fetch error', err);
|
|
98
|
+
next();
|
|
99
|
+
reject(err);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
const headerNow = Date.parse(response.headers.get('date') ?? '');
|
|
104
|
+
this.setRatelimitsBucket(route, response);
|
|
105
|
+
this.setResetBucket(route, response, now, headerNow);
|
|
106
|
+
let result = await response.text();
|
|
107
|
+
if (response.status >= 300) {
|
|
108
|
+
if (response.status === 429) {
|
|
109
|
+
const result429 = await this.handle429(route, method, url, request, response, result, next, reject, now);
|
|
110
|
+
if (result429 !== false)
|
|
111
|
+
return resolve(result429);
|
|
112
|
+
return this.clearResetInterval(route);
|
|
113
|
+
}
|
|
114
|
+
if ([502, 503].includes(response.status) && ++attempts < 4) {
|
|
115
|
+
this.clearResetInterval(route);
|
|
116
|
+
return this.handle50X(method, url, request, next);
|
|
117
|
+
}
|
|
118
|
+
this.clearResetInterval(route);
|
|
119
|
+
next();
|
|
120
|
+
if (result.length > 0) {
|
|
121
|
+
if (response.headers.get('content-type') === 'application/json') {
|
|
122
|
+
try {
|
|
123
|
+
result = JSON.parse(result);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
this.debugger?.warn('Error parsing result error (', result, ')', err);
|
|
127
|
+
reject(err);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const parsedError = this.parseError(response, result);
|
|
133
|
+
this.debugger?.warn(parsedError);
|
|
134
|
+
reject(parsedError);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (result.length > 0) {
|
|
138
|
+
if (response.headers.get('content-type') === 'application/json') {
|
|
139
|
+
try {
|
|
140
|
+
result = JSON.parse(result);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
this.debugger?.warn('Error parsing result (', result, ')', err);
|
|
144
|
+
next();
|
|
145
|
+
reject(err);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
next();
|
|
151
|
+
return resolve((result || undefined));
|
|
152
|
+
};
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
if (this.globalBlock && auth) {
|
|
155
|
+
this.readyQueue.push(() => {
|
|
156
|
+
if (!this.ratelimits.has(route)) {
|
|
157
|
+
this.ratelimits.set(route, new bucket_1.Bucket(1));
|
|
158
|
+
}
|
|
159
|
+
this.ratelimits.get(route).push({ next: callback, resolve, reject }, request.unshift);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
if (!this.ratelimits.has(route)) {
|
|
164
|
+
this.ratelimits.set(route, new bucket_1.Bucket(1));
|
|
165
|
+
}
|
|
166
|
+
this.ratelimits.get(route).push({ next: callback, resolve, reject }, request.unshift);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
parseError(response, result) {
|
|
171
|
+
let errMessage = '';
|
|
172
|
+
if (typeof result === 'object' && result) {
|
|
173
|
+
if ('message' in result) {
|
|
174
|
+
errMessage += `${result.message}${'code' in result ? ` ${result.code}` : ''}\n`;
|
|
175
|
+
}
|
|
176
|
+
if ('errors' in result && result) {
|
|
177
|
+
errMessage += `${JSON.stringify(result.errors, null, 2)}\n`;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (response.status) {
|
|
181
|
+
return new Error(errMessage ?? response.statusText);
|
|
182
|
+
}
|
|
183
|
+
return new Error('Unknown error');
|
|
184
|
+
}
|
|
185
|
+
async handle50X(method, url, request, next) {
|
|
186
|
+
const wait = Math.floor(Math.random() * 1900 + 100);
|
|
187
|
+
this.debugger?.warn(`Handling a 50X status, retrying in ${wait}ms`);
|
|
188
|
+
next();
|
|
189
|
+
await (0, promises_1.setTimeout)(wait);
|
|
190
|
+
return this.request(method, url, {
|
|
191
|
+
body: request.body,
|
|
192
|
+
auth: request.auth,
|
|
193
|
+
reason: request.reason,
|
|
194
|
+
route: request.route,
|
|
195
|
+
unshift: true,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async handle429(route, method, url, request, response, result, next, reject, now) {
|
|
199
|
+
const content = typeof request === 'object' ? `${JSON.stringify(request)} ` : '';
|
|
200
|
+
let retryAfter;
|
|
201
|
+
try {
|
|
202
|
+
retryAfter = JSON.parse(result).retry_after * 1000;
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
this.debugger?.warn(`Unexpected error: ${err}`);
|
|
206
|
+
reject(err);
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
this.debugger?.info(`${response.headers.get('x-ratelimit-global') ? 'Global' : 'Unexpected'} 429: ${result}\n${content} ${now} ${route} ${response.status}: ${this.ratelimits.get(route).remaining}/${this.ratelimits.get(route).limit} left | Reset ${retryAfter} (${this.ratelimits.get(route).reset - now}ms left) | Scope ${response.headers.get('x-ratelimit-scope')}`);
|
|
210
|
+
if (retryAfter) {
|
|
211
|
+
await (0, promises_1.setTimeout)(retryAfter);
|
|
212
|
+
next();
|
|
213
|
+
return this.request(method, url, {
|
|
214
|
+
body: request.body,
|
|
215
|
+
auth: request.auth,
|
|
216
|
+
reason: request.reason,
|
|
217
|
+
route: request.route,
|
|
218
|
+
unshift: true,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
next();
|
|
222
|
+
return this.request(method, url, {
|
|
223
|
+
body: request.body,
|
|
224
|
+
auth: request.auth,
|
|
225
|
+
reason: request.reason,
|
|
226
|
+
route: request.route,
|
|
227
|
+
unshift: true,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
clearResetInterval(route) {
|
|
231
|
+
clearInterval(this.ratelimits.get(route).processingResetAfter);
|
|
232
|
+
this.ratelimits.get(route).processingResetAfter = undefined;
|
|
233
|
+
this.ratelimits.get(route).resetAfter = 0;
|
|
234
|
+
}
|
|
235
|
+
setResetBucket(route, resp, now, headerNow) {
|
|
236
|
+
const retryAfter = Number(resp.headers.get('x-ratelimit-reset-after') || resp.headers.get('retry-after')) * 1000;
|
|
237
|
+
if (retryAfter >= 0) {
|
|
238
|
+
if (resp.headers.get('x-ratelimit-global')) {
|
|
239
|
+
this.globalBlock = true;
|
|
240
|
+
setTimeout(() => this.globalUnblock(), retryAfter || 1);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
this.ratelimits.get(route).reset = (retryAfter || 1) + now;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
else if (resp.headers.get('x-ratelimit-reset')) {
|
|
247
|
+
let resetTime = +resp.headers.get('x-ratelimit-reset') * 1000;
|
|
248
|
+
if (route.endsWith('/reactions/:id') && +resp.headers.get('x-ratelimit-reset') * 1000 - headerNow === 1000) {
|
|
249
|
+
resetTime = now + 250;
|
|
250
|
+
}
|
|
251
|
+
this.ratelimits.get(route).reset = Math.max(resetTime, now);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
this.ratelimits.get(route).reset = now;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
setRatelimitsBucket(route, resp) {
|
|
258
|
+
if (resp.headers.get('x-ratelimit-limit')) {
|
|
259
|
+
this.ratelimits.get(route).limit = +resp.headers.get('x-ratelimit-limit');
|
|
260
|
+
}
|
|
261
|
+
this.ratelimits.get(route).remaining =
|
|
262
|
+
resp.headers.get('x-ratelimit-remaining') === undefined ? 1 : +resp.headers.get('x-ratelimit-remaining');
|
|
263
|
+
if (this.options.smartBucket) {
|
|
264
|
+
if (resp.headers.get('x-ratelimit-reset-after') &&
|
|
265
|
+
!this.ratelimits.get(route).resetAfter &&
|
|
266
|
+
Number(resp.headers.get('x-ratelimit-limit')) === Number(resp.headers.get('x-ratelimit-remaining')) + 1) {
|
|
267
|
+
this.ratelimits.get(route).resetAfter = +resp.headers.get('x-ratelimit-reset-after') * 1000;
|
|
268
|
+
}
|
|
269
|
+
if (this.ratelimits.get(route).resetAfter && !this.ratelimits.get(route).remaining) {
|
|
270
|
+
this.ratelimits.get(route).triggerResetAfter();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
parseRequest(options) {
|
|
275
|
+
let finalUrl = options.url;
|
|
276
|
+
let data;
|
|
277
|
+
if (options.request.auth) {
|
|
278
|
+
options.headers.Authorization = `Bot ${this.options.token}`;
|
|
279
|
+
}
|
|
280
|
+
if (options.request.query) {
|
|
281
|
+
finalUrl += `?${new URLSearchParams(options.request.query)}`;
|
|
282
|
+
}
|
|
283
|
+
if (options.request.files) {
|
|
284
|
+
const formData = new FormData();
|
|
285
|
+
for (const [index, file] of options.request.files.entries()) {
|
|
286
|
+
const fileKey = file.key ?? `files[${index}]`;
|
|
287
|
+
if ((0, utils_1.isBufferLike)(file.data)) {
|
|
288
|
+
let contentType = file.contentType;
|
|
289
|
+
if (!contentType) {
|
|
290
|
+
const [parsedType] = (0, magic_bytes_js_1.filetypeinfo)(file.data);
|
|
291
|
+
if (parsedType) {
|
|
292
|
+
contentType =
|
|
293
|
+
shared_1.OverwrittenMimeTypes[parsedType.mime] ??
|
|
294
|
+
parsedType.mime ??
|
|
295
|
+
'application/octet-stream';
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
formData.append(fileKey, new Blob([file.data], { type: contentType }), file.name);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
formData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (options.request.body) {
|
|
305
|
+
if (options.request.appendToFormData) {
|
|
306
|
+
for (const [key, value] of Object.entries(options.request.body)) {
|
|
307
|
+
formData.append(key, value);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
formData.append('payload_json', JSON.stringify(options.request.body));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
data = formData;
|
|
315
|
+
}
|
|
316
|
+
else if (options.request.body) {
|
|
317
|
+
options.headers['Content-Type'] = 'application/json';
|
|
318
|
+
data = JSON.stringify(options.request.body);
|
|
319
|
+
}
|
|
320
|
+
if (options.request.reason) {
|
|
321
|
+
options.headers['X-Audit-Log-Reason'] = encodeURIComponent(options.request.reason);
|
|
322
|
+
}
|
|
323
|
+
return { data, finalUrl };
|
|
324
|
+
}
|
|
325
|
+
routefy(url, method) {
|
|
326
|
+
let route = url
|
|
327
|
+
.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, (match, p) => p === 'channels' || p === 'guilds' || p === 'webhooks' ? match : `/${p}/:id`)
|
|
328
|
+
.replace(/\/reactions\/[^/]+/g, '/reactions/:id')
|
|
329
|
+
.replace(/\/reactions\/:id\/[^/]+/g, '/reactions/:id/:userID')
|
|
330
|
+
.replace(/^\/webhooks\/(\d+)\/[A-Za-z0-9-_]{64,}/, '/webhooks/$1/:token');
|
|
331
|
+
if (method === 'DELETE' && route.endsWith('/messages/:id')) {
|
|
332
|
+
const messageID = url.slice(url.lastIndexOf('/') + 1);
|
|
333
|
+
const createdAt = Number((0, functions_1.snowflakeToTimestamp)(messageID));
|
|
334
|
+
if (Date.now() - createdAt >= 1000 * 60 * 60 * 24 * 14) {
|
|
335
|
+
method += '_OLD';
|
|
336
|
+
}
|
|
337
|
+
else if (Date.now() - createdAt <= 1000 * 10) {
|
|
338
|
+
method += '_NEW';
|
|
339
|
+
}
|
|
340
|
+
route = method + route;
|
|
341
|
+
}
|
|
342
|
+
else if (method === 'GET' && /\/guilds\/[0-9]+\/channels$/.test(route)) {
|
|
343
|
+
route = '/guilds/:id/channels';
|
|
344
|
+
}
|
|
345
|
+
if (method === 'PUT' || method === 'DELETE') {
|
|
346
|
+
const index = route.indexOf('/reactions');
|
|
347
|
+
if (index !== -1) {
|
|
348
|
+
route = `MODIFY${route.slice(0, index + 10)}`;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return route;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
exports.ApiHandler = ApiHandler;
|