@discordjs/rest 0.2.0-canary.0 → 0.3.0-dev.1644408653.fe11ff5

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.
@@ -4,6 +4,9 @@ import { CDN } from './CDN';
4
4
  import { InternalRequest, RequestData, RequestManager, RouteLike } from './RequestManager';
5
5
  import type { AgentOptions } from 'node:https';
6
6
  import type { RequestInit, Response } from 'node-fetch';
7
+ import type { HashData } from './RequestManager';
8
+ import type Collection from '@discordjs/collection';
9
+ import type { IHandler } from './handlers/IHandler';
7
10
  /**
8
11
  * Options to be passed when creating the REST instance
9
12
  */
@@ -73,6 +76,21 @@ export interface RESTOptions {
73
76
  * @default '9'
74
77
  */
75
78
  version: string;
79
+ /**
80
+ * The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h)
81
+ * @default 14_400_000
82
+ */
83
+ hashSweepInterval: number;
84
+ /**
85
+ * The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h)
86
+ * @default 86_400_000
87
+ */
88
+ hashLifetime: number;
89
+ /**
90
+ * The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h)
91
+ * @default 3_600_000
92
+ */
93
+ handlerSweepInterval: number;
76
94
  }
77
95
  /**
78
96
  * Data emitted on `RESTEvents.RateLimited`
@@ -138,7 +156,7 @@ export interface APIRequest {
138
156
  /**
139
157
  * The data that was used to form the body of this request
140
158
  */
141
- data: Pick<InternalRequest, 'attachments' | 'body'>;
159
+ data: Pick<InternalRequest, 'files' | 'body'>;
142
160
  /**
143
161
  * The number of times this request has been attempted
144
162
  */
@@ -150,7 +168,7 @@ export interface InvalidRequestWarningData {
150
168
  */
151
169
  count: number;
152
170
  /**
153
- * Time in ms remaining before the count resets
171
+ * Time in milliseconds remaining before the count resets
154
172
  */
155
173
  remainingTime: number;
156
174
  }
@@ -162,18 +180,15 @@ export interface RestEvents {
162
180
  response: [request: APIRequest, response: Response];
163
181
  newListener: [name: string, listener: (...args: any) => void];
164
182
  removeListener: [name: string, listener: (...args: any) => void];
183
+ hashSweep: [sweptHashes: Collection<string, HashData>];
184
+ handlerSweep: [sweptHandlers: Collection<string, IHandler>];
165
185
  }
166
186
  export interface REST {
167
- on<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this;
168
- on<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this;
169
- once<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this;
170
- once<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this;
171
- emit<K extends keyof RestEvents>(event: K, ...args: RestEvents[K]): boolean;
172
- emit<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, ...args: any[]): boolean;
173
- off<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this;
174
- off<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this;
175
- removeAllListeners<K extends keyof RestEvents>(event?: K): this;
176
- removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>): this;
187
+ on: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this);
188
+ once: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this);
189
+ emit: (<K extends keyof RestEvents>(event: K, ...args: RestEvents[K]) => boolean) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, ...args: any[]) => boolean);
190
+ off: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this);
191
+ removeAllListeners: (<K extends keyof RestEvents>(event?: K) => this) & (<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>) => this);
177
192
  }
178
193
  export declare class REST extends EventEmitter {
179
194
  readonly cdn: CDN;
@@ -1,39 +1,36 @@
1
1
  /// <reference types="node" />
2
2
  import Collection from '@discordjs/collection';
3
3
  import { EventEmitter } from 'node:events';
4
+ import type { BodyInit } from 'node-fetch';
4
5
  import type { IHandler } from './handlers/IHandler';
5
6
  import type { RESTOptions, RestEvents } from './REST';
6
7
  /**
7
- * Represents an attachment to be added to the request
8
+ * Represents a file to be added to the request
8
9
  */
9
- export interface RawAttachment {
10
+ export interface RawFile {
10
11
  /**
11
12
  * The name of the file
12
13
  */
13
- fileName: string;
14
+ name: string;
14
15
  /**
15
- * An explicit key to use for key of the formdata field for this attachment.
16
- * When not provided, the index of the file in the attachments array is used in the form `files[${index}]`.
16
+ * An explicit key to use for key of the formdata field for this file.
17
+ * When not provided, the index of the file in the files array is used in the form `files[${index}]`.
17
18
  * If you wish to alter the placeholder snowflake, you must provide this property in the same form (`files[${placeholder}]`)
18
19
  */
19
20
  key?: string;
20
21
  /**
21
- * The actual data for the attachment
22
+ * The actual data for the file
22
23
  */
23
- rawBuffer: Buffer;
24
+ data: string | number | boolean | Buffer;
24
25
  }
25
26
  /**
26
27
  * Represents possible data to be given to an endpoint
27
28
  */
28
29
  export interface RequestData {
29
30
  /**
30
- * Whether to append JSON data to form data instead of `payload_json` when sending attachments
31
+ * Whether to append JSON data to form data instead of `payload_json` when sending files
31
32
  */
32
33
  appendToFormData?: boolean;
33
- /**
34
- * Files to be attached to this request
35
- */
36
- attachments?: RawAttachment[] | undefined;
37
34
  /**
38
35
  * If this request needs the `Authorization` header
39
36
  * @default true
@@ -45,13 +42,23 @@ export interface RequestData {
45
42
  */
46
43
  authPrefix?: 'Bot' | 'Bearer';
47
44
  /**
48
- * The body to send to this request
45
+ * The body to send to this request.
46
+ * If providing as BodyInit, set `passThroughBody: true`
49
47
  */
50
- body?: unknown;
48
+ body?: BodyInit | unknown;
49
+ /**
50
+ * Files to be attached to this request
51
+ */
52
+ files?: RawFile[] | undefined;
51
53
  /**
52
54
  * Additional headers to add to this request
53
55
  */
54
56
  headers?: Record<string, string>;
57
+ /**
58
+ * Whether to pass-through the body property directly to `fetch()`.
59
+ * <warn>This only applies when files is NOT present</warn>
60
+ */
61
+ passThroughBody?: boolean;
55
62
  /**
56
63
  * Query string parameters to append to the called endpoint
57
64
  */
@@ -104,17 +111,21 @@ export interface RouteData {
104
111
  bucketRoute: string;
105
112
  original: RouteLike;
106
113
  }
114
+ /**
115
+ * Represents a hash and its associated fields
116
+ *
117
+ * @internal
118
+ */
119
+ export interface HashData {
120
+ value: string;
121
+ lastAccess: number;
122
+ }
107
123
  export interface RequestManager {
108
- on<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this;
109
- on<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this;
110
- once<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this;
111
- once<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this;
112
- emit<K extends keyof RestEvents>(event: K, ...args: RestEvents[K]): boolean;
113
- emit<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, ...args: any[]): boolean;
114
- off<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void): this;
115
- off<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void): this;
116
- removeAllListeners<K extends keyof RestEvents>(event?: K): this;
117
- removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>): this;
124
+ on: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this);
125
+ once: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this);
126
+ emit: (<K extends keyof RestEvents>(event: K, ...args: RestEvents[K]) => boolean) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, ...args: any[]) => boolean);
127
+ off: (<K extends keyof RestEvents>(event: K, listener: (...args: RestEvents[K]) => void) => this) & (<S extends string | symbol>(event: Exclude<S, keyof RestEvents>, listener: (...args: any[]) => void) => this);
128
+ removeAllListeners: (<K extends keyof RestEvents>(event?: K) => this) & (<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>) => this);
118
129
  }
119
130
  /**
120
131
  * Represents the class that manages handlers for endpoints
@@ -136,13 +147,17 @@ export declare class RequestManager extends EventEmitter {
136
147
  /**
137
148
  * API bucket hashes that are cached from provided routes
138
149
  */
139
- readonly hashes: Collection<string, string>;
150
+ readonly hashes: Collection<string, HashData>;
140
151
  /**
141
152
  * Request handlers created from the bucket hash and the major parameters
142
153
  */
143
154
  readonly handlers: Collection<string, IHandler>;
155
+ private hashTimer;
156
+ private handlerTimer;
157
+ private agent;
144
158
  readonly options: RESTOptions;
145
159
  constructor(options: Partial<RESTOptions>);
160
+ private setupSweepers;
146
161
  /**
147
162
  * Sets the authorization token that should be used for requests
148
163
  * @param token The authorization token to use
@@ -166,6 +181,14 @@ export declare class RequestManager extends EventEmitter {
166
181
  * @param request The request data
167
182
  */
168
183
  private resolveRequest;
184
+ /**
185
+ * Stops the hash sweeping interval
186
+ */
187
+ clearHashSweeper(): void;
188
+ /**
189
+ * Stops the request handler sweeping interval
190
+ */
191
+ clearHandlerSweeper(): void;
169
192
  /**
170
193
  * Generates route data for an endpoint:method
171
194
  * @param endpoint The raw endpoint to generalize
@@ -1,4 +1,4 @@
1
- import type { InternalRequest, RawAttachment } from '../RequestManager';
1
+ import type { InternalRequest, RawFile } from '../RequestManager';
2
2
  interface DiscordErrorFieldInformation {
3
3
  code: string;
4
4
  message: string;
@@ -14,8 +14,12 @@ export interface DiscordErrorData {
14
14
  message: string;
15
15
  errors?: DiscordError;
16
16
  }
17
+ export interface OAuthErrorData {
18
+ error: string;
19
+ error_description?: string;
20
+ }
17
21
  export interface RequestBody {
18
- attachments: RawAttachment[] | undefined;
22
+ files: RawFile[] | undefined;
19
23
  json: unknown | undefined;
20
24
  }
21
25
  /**
@@ -23,8 +27,8 @@ export interface RequestBody {
23
27
  * @extends Error
24
28
  */
25
29
  export declare class DiscordAPIError extends Error {
26
- rawError: DiscordErrorData;
27
- code: number;
30
+ rawError: DiscordErrorData | OAuthErrorData;
31
+ code: number | string;
28
32
  status: number;
29
33
  method: string;
30
34
  url: string;
@@ -37,7 +41,7 @@ export declare class DiscordAPIError extends Error {
37
41
  * @param url The url of the request that erred
38
42
  * @param bodyData The unparsed data for the request that errored
39
43
  */
40
- constructor(rawError: DiscordErrorData, code: number, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'attachments' | 'body'>);
44
+ constructor(rawError: DiscordErrorData | OAuthErrorData, code: number | string, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'files' | 'body'>);
41
45
  /**
42
46
  * The name of the error
43
47
  */
@@ -17,5 +17,5 @@ export declare class HTTPError extends Error {
17
17
  * @param url The url of the request that erred
18
18
  * @param bodyData The unparsed data for the request that errored
19
19
  */
20
- constructor(message: string, name: string, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'attachments' | 'body'>);
20
+ constructor(message: string, name: string, status: number, method: string, url: string, bodyData: Pick<InternalRequest, 'files' | 'body'>);
21
21
  }
@@ -1,5 +1,7 @@
1
1
  import type { RequestInit } from 'node-fetch';
2
2
  import type { InternalRequest, RouteData } from '../RequestManager';
3
3
  export interface IHandler {
4
- queueRequest(routeId: RouteData, url: string, options: RequestInit, bodyData: Pick<InternalRequest, 'attachments' | 'body'>): Promise<unknown>;
4
+ queueRequest: (routeId: RouteData, url: string, options: RequestInit, bodyData: Pick<InternalRequest, 'files' | 'body'>) => Promise<unknown>;
5
+ readonly inactive: boolean;
6
+ readonly id: string;
5
7
  }
@@ -69,7 +69,7 @@ export declare class SequentialHandler {
69
69
  * @param options All the information needed to make a request
70
70
  * @param bodyData The data that was used to form the body, passed to any errors generated and for determining whether to sublimit
71
71
  */
72
- queueRequest(routeId: RouteData, url: string, options: RequestInit, bodyData: Pick<InternalRequest, 'attachments' | 'body'>): Promise<unknown>;
72
+ queueRequest(routeId: RouteData, url: string, options: RequestInit, bodyData: Pick<InternalRequest, 'files' | 'body'>): Promise<unknown>;
73
73
  /**
74
74
  * The method that actually makes the request to the api, and updates info about the bucket accordingly
75
75
  * @param routeId The generalized api route with literal ids for major parameters
@@ -9,7 +9,9 @@ export declare const enum RESTEvents {
9
9
  InvalidRequestWarning = "invalidRequestWarning",
10
10
  RateLimited = "rateLimited",
11
11
  Request = "request",
12
- Response = "response"
12
+ Response = "response",
13
+ HashSweep = "hashSweep",
14
+ HandlerSweep = "handlerSweep"
13
15
  }
14
16
  export declare const ALLOWED_EXTENSIONS: readonly ["webp", "png", "jpg", "jpeg", "gif"];
15
17
  export declare const ALLOWED_STICKER_EXTENSIONS: readonly ["png", "json"];
package/package.json CHANGED
@@ -1,65 +1,90 @@
1
1
  {
2
- "name": "@discordjs/rest",
3
- "version": "0.2.0-canary.0",
4
- "description": "The REST API for discord.js",
5
- "scripts": {
6
- "test": "echo \"Error: run tests from root\" && exit 1",
7
- "build": "tsup && tsc --emitDeclarationOnly"
8
- },
9
- "main": "./dist/index.js",
10
- "module": "./dist/index.mjs",
11
- "typings": "./dist/index.d.ts",
12
- "exports": {
13
- "import": "./dist/index.mjs",
14
- "require": "./dist/index.js"
15
- },
16
- "directories": {
17
- "lib": "src",
18
- "test": "__tests__"
19
- },
20
- "files": [
21
- "dist"
22
- ],
23
- "contributors": [
24
- "Crawl <icrawltogo@gmail.com>",
25
- "Amish Shah <amishshah.2k@gmail.com>",
26
- "SpaceEEC <spaceeec@yahoo.com>",
27
- "Vlad Frangu <kingdgrizzle@gmail.com>",
28
- "Antonio Roman <kyradiscord@gmail.com>"
29
- ],
30
- "license": "Apache-2.0",
31
- "keywords": [
32
- "discord",
33
- "api",
34
- "rest",
35
- "discordapp",
36
- "discordjs"
37
- ],
38
- "repository": {
39
- "type": "git",
40
- "url": "git+https://github.com/discordjs/discord.js-modules.git"
41
- },
42
- "bugs": {
43
- "url": "https://github.com/discordjs/discord.js-modules/issues"
44
- },
45
- "homepage": "https://github.com/discordjs/discord.js-modules/tree/main/packages/rest",
46
- "dependencies": {
47
- "@discordjs/collection": "^0.3.2",
48
- "@sapphire/async-queue": "^1.1.9",
49
- "@sapphire/snowflake": "^3.0.0",
50
- "discord-api-types": "^0.25.2",
51
- "form-data": "^4.0.0",
52
- "node-fetch": "^2.6.5",
53
- "tslib": "^2.3.1"
54
- },
55
- "devDependencies": {
56
- "@types/node-fetch": "^2.5.10"
57
- },
58
- "engines": {
59
- "node": ">=16.0.0"
60
- },
61
- "publishConfig": {
62
- "access": "public"
63
- },
64
- "gitHead": "d006f270fd911e178b0b6f83cbfa88aa2ef626b7"
65
- }
2
+ "name": "@discordjs/rest",
3
+ "version": "0.3.0-dev.1644408653.fe11ff5",
4
+ "description": "The REST API for discord.js",
5
+ "scripts": {
6
+ "build": "tsup && tsc --emitDeclarationOnly --incremental",
7
+ "test": "jest --pass-with-no-tests --collect-coverage",
8
+ "lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
9
+ "format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
10
+ "docs": "typedoc --json docs/typedoc-out.json src/index.ts && node scripts/docs.mjs",
11
+ "prepublishOnly": "yarn build && yarn lint && yarn test",
12
+ "changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/rest/*'"
13
+ },
14
+ "main": "./dist/index.js",
15
+ "module": "./dist/index.mjs",
16
+ "typings": "./dist/index.d.ts",
17
+ "exports": {
18
+ "import": "./dist/index.mjs",
19
+ "require": "./dist/index.js"
20
+ },
21
+ "directories": {
22
+ "lib": "src",
23
+ "test": "__tests__"
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "contributors": [
29
+ "Crawl <icrawltogo@gmail.com>",
30
+ "Amish Shah <amishshah.2k@gmail.com>",
31
+ "SpaceEEC <spaceeec@yahoo.com>",
32
+ "Vlad Frangu <kingdgrizzle@gmail.com>",
33
+ "Antonio Roman <kyradiscord@gmail.com>"
34
+ ],
35
+ "license": "Apache-2.0",
36
+ "keywords": [
37
+ "discord",
38
+ "api",
39
+ "rest",
40
+ "discordapp",
41
+ "discordjs"
42
+ ],
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/discordjs/discord.js.git"
46
+ },
47
+ "bugs": {
48
+ "url": "https://github.com/discordjs/discord.js/issues"
49
+ },
50
+ "homepage": "https://discord.js.org",
51
+ "dependencies": {
52
+ "@discordjs/collection": "^0.6.0-dev",
53
+ "@sapphire/async-queue": "^1.2.0",
54
+ "@sapphire/snowflake": "^3.1.0",
55
+ "@types/node-fetch": "^2.5.12",
56
+ "discord-api-types": "^0.26.1",
57
+ "form-data": "^4.0.0",
58
+ "node-fetch": "^2.6.7",
59
+ "tslib": "^2.3.1"
60
+ },
61
+ "devDependencies": {
62
+ "@babel/core": "^7.17.0",
63
+ "@babel/plugin-proposal-decorators": "^7.17.0",
64
+ "@babel/preset-env": "^7.16.11",
65
+ "@babel/preset-typescript": "^7.16.7",
66
+ "@discordjs/ts-docgen": "^0.3.4",
67
+ "@types/jest": "^27.4.0",
68
+ "@typescript-eslint/eslint-plugin": "^5.10.2",
69
+ "@typescript-eslint/parser": "^5.10.2",
70
+ "babel-plugin-const-enum": "^1.2.0",
71
+ "babel-plugin-transform-typescript-metadata": "^0.3.2",
72
+ "eslint": "^8.8.0",
73
+ "eslint-config-marine": "^9.3.2",
74
+ "eslint-config-prettier": "^8.3.0",
75
+ "eslint-plugin-prettier": "^4.0.0",
76
+ "jest": "^27.4.7",
77
+ "nock": "^13.2.4",
78
+ "prettier": "^2.5.1",
79
+ "tsup": "^5.11.13",
80
+ "typedoc": "^0.22.11",
81
+ "typescript": "^4.5.5"
82
+ },
83
+ "engines": {
84
+ "node": ">=16.9.0"
85
+ },
86
+ "publishConfig": {
87
+ "access": "public"
88
+ },
89
+ "stableVersion": "0.3.0-dev"
90
+ }