unb-api 1.3.2 → 1.4.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/README.md +143 -59
- package/index.d.ts +10 -8
- package/package.json +2 -2
- package/src/lib/Client.js +30 -1
- package/src/lib/RequestHandler.js +59 -59
- package/src/lib/errors/APIError.js +6 -11
- package/src/lib/errors/HTTPError.js +6 -1
package/README.md
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
# UnbelievaBoat API
|
|
2
2
|
|
|
3
|
-
[](https://discord.gg/
|
|
3
|
+
[](https://discord.gg/unb)
|
|
4
4
|
[](https://www.npmjs.com/package/unb-api)
|
|
5
5
|
[](https://www.npmjs.com/package/unb-api)
|
|
6
6
|
[](https://github.com/ellerbrock/open-source-badge/)
|
|
7
7
|
[](https://nodei.co/npm/unb-api/)
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
|
+
|
|
10
11
|
`npm install unb-api`
|
|
11
12
|
|
|
12
13
|
## Documentation
|
|
14
|
+
|
|
13
15
|
Full API documentation is located at [https://unbelievaboat.com/api/docs](https://unbelievaboat.com/api/docs)
|
|
14
16
|
|
|
15
17
|
### Example
|
|
18
|
+
|
|
16
19
|
```javascript
|
|
17
20
|
const { Client } = require('unb-api');
|
|
18
21
|
const client = new Client('TOKEN'); // Get your API token from https://unbelievaboat.com/api/docs
|
|
@@ -25,84 +28,165 @@ client.getGuildLeaderboard(guildID, { sort: 'cash' }).then(lb => console.log(lb)
|
|
|
25
28
|
```
|
|
26
29
|
|
|
27
30
|
### Constructor
|
|
31
|
+
|
|
28
32
|
`new Client(token, [options])`
|
|
29
33
|
|
|
30
34
|
##### Options
|
|
31
|
-
Type | Property | Description
|
|
32
|
-
------- | --------- | -----------
|
|
33
|
-
String | `baseURL?` | API hostname. Defaults to https://unbelievaboat.com/api
|
|
34
|
-
Number | `version?` | API version. Defaults to the latest version
|
|
35
|
-
Number | `maxRetries?` | Maximum number of times to retry a request if it's ratelimited. Defaults to 3
|
|
36
35
|
|
|
36
|
+
| Type | Property | Description |
|
|
37
|
+
|--------|---------------|--------------------------------------------------------------------------------|
|
|
38
|
+
| String | `baseURL?` | API hostname. Defaults to https://unbelievaboat.com/api |
|
|
39
|
+
| Number | `version?` | API version. Defaults to the latest version |
|
|
40
|
+
| Number | `maxRetries?` | Maximum number of times to retry a request if it's rate-limited. Defaults to 3 |
|
|
37
41
|
|
|
38
42
|
### Methods
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
|
|
44
|
+
#### Economy
|
|
45
|
+
|
|
46
|
+
`getUserBalance(guildId: string, userId: string)`
|
|
42
47
|
Returns: `Promise<User>`
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
setUserBalance(guild_id, user_id, { cash, bank }, reason)
|
|
46
|
-
```
|
|
48
|
+
|
|
49
|
+
`setUserBalance(guildId: string, userId: string, balance: Balance, reason?: string)`
|
|
47
50
|
Returns: `Promise<User>`
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
editUserBalance(guild_id, user_id, { cash, bank }, reason)
|
|
51
|
-
```
|
|
51
|
+
|
|
52
|
+
`editUserBalance(guildId: string, userId: string, balance: Balance, reason?: string)`
|
|
52
53
|
Returns: `Promise<User>`
|
|
53
|
-
#
|
|
54
|
-
```
|
|
55
|
-
getGuildLeaderboard(guild_id, [query])
|
|
56
|
-
```
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Number | `offset?` | Specify the offset of the first user.
|
|
64
|
-
Number | `page?` | Specify the page. If a page is given, the response will be `Promise<{ users: User[], totalPages: Number }>`
|
|
55
|
+
`getGuildLeaderboard(guildId: string, query?: ListOptions)`
|
|
56
|
+
Returns: `Promise<User[]> | Promise<{ users: User[], totalPages: number }>`
|
|
57
|
+
> [!NOTE]
|
|
58
|
+
> If the query for `getGuildLeaderboard` includes a page parameter, the response will be an object containing both users and totalPages.
|
|
59
|
+
> Otherwise, it will return a simple array of User[].
|
|
65
60
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
getGuild(guild_id)
|
|
70
|
-
```
|
|
61
|
+
#### Generic
|
|
62
|
+
|
|
63
|
+
`getGuild(guildId: string)`
|
|
71
64
|
Returns: `Promise<Guild>`
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
getApplicationPermission(guild_id)
|
|
75
|
-
```
|
|
65
|
+
|
|
66
|
+
`getApplicationPermission(guildId: string)`
|
|
76
67
|
Returns: `Promise<Permission>`
|
|
77
68
|
|
|
69
|
+
#### Items
|
|
70
|
+
|
|
71
|
+
`getItems(guildId: string, options?: ListOptions)`
|
|
72
|
+
Returns: `Promise<{ page: number, totalPages: number, items: StoreItem[] }>`
|
|
73
|
+
|
|
74
|
+
`getItem(guildId: string, itemId: string)`
|
|
75
|
+
Returns: `Promise<StoreItem>`
|
|
76
|
+
|
|
77
|
+
`createItem(guildId: string)`
|
|
78
|
+
Returns: `Promise<StoreItem>`
|
|
79
|
+
|
|
80
|
+
`editItem(guildId: string, itemId: string, data: StoreItem | object, options?: { cascadeUpdate?: boolean })`
|
|
81
|
+
Returns: `Promise<StoreItem>`
|
|
82
|
+
|
|
83
|
+
`deleteItem(guildId: string, itemId: string)`
|
|
84
|
+
Returns: `Promise<any>`
|
|
85
|
+
|
|
86
|
+
`getInventoryItems(guildId: string, userId: string, options?: ListOptions)`
|
|
87
|
+
Returns: `Promise<{ page: number, totalPages: number, items: InventoryItem[] }>`
|
|
88
|
+
|
|
89
|
+
`getInventoryItem(guildId: string, userId: string, itemId: string)`
|
|
90
|
+
Returns: `Promise<InventoryItem>`
|
|
91
|
+
|
|
92
|
+
`addInventoryItem(guildId: string, userId: string, itemId: string, quantity?: string | number, options?: { inventoryUserId?: string })`
|
|
93
|
+
Returns: `Promise<InventoryItem>`
|
|
94
|
+
|
|
95
|
+
`removeInventoryItem(guildId: string, userId: string, itemId: string, quantity?: string | number)`
|
|
96
|
+
Returns: `Promise<any>`
|
|
97
|
+
|
|
98
|
+
##### ListOptions Parameters
|
|
99
|
+
|
|
100
|
+
| Type | Property |
|
|
101
|
+
|----------|-----------|
|
|
102
|
+
| String[] | `sort?` |
|
|
103
|
+
| Number | `limit?` |
|
|
104
|
+
| Number | `offset?` |
|
|
105
|
+
| Number | `page?` |
|
|
106
|
+
|
|
78
107
|
### Structures
|
|
108
|
+
|
|
79
109
|
#### User
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
Number | `
|
|
86
|
-
Number | `
|
|
87
|
-
|
|
110
|
+
|
|
111
|
+
| Type | Property | Description |
|
|
112
|
+
|--------|-----------|--------------------------------------------------------------------------------------------------|
|
|
113
|
+
| Number | `rank?` | Leaderboard rank of the user. This is only present on getUserBalance() and getGuildLeaderboard() |
|
|
114
|
+
| String | `user_id` | User ID of the discord user. |
|
|
115
|
+
| Number | `cash` | User's cash balance. |
|
|
116
|
+
| Number | `bank` | User's bank balance. |
|
|
117
|
+
| Number | `total` | User's total balance. |
|
|
118
|
+
|
|
88
119
|
#### Guild
|
|
89
|
-
Type | Property | Description
|
|
90
|
-
--- | --- | ---
|
|
91
|
-
String | `id` | Guild ID.
|
|
92
|
-
String | `name` | Guild name.
|
|
93
|
-
Number | `icon` | Icon hash.
|
|
94
|
-
Number | `iconURL` | Icon url.
|
|
95
|
-
String | `ownerID` | User ID of the owner.
|
|
96
|
-
Number | `memberCount` | Total number of members.
|
|
97
|
-
String | `currencySymbol` | Currency symbol
|
|
98
120
|
|
|
121
|
+
| Type | Property | Description |
|
|
122
|
+
|--------|------------------|--------------------------|
|
|
123
|
+
| String | `id` | Guild ID. |
|
|
124
|
+
| String | `name` | Guild name. |
|
|
125
|
+
| Number | `icon` | Icon hash. |
|
|
126
|
+
| Number | `iconURL` | Icon url. |
|
|
127
|
+
| String | `ownerID` | User ID of the owner. |
|
|
128
|
+
| Number | `memberCount` | Total number of members. |
|
|
129
|
+
| String | `currencySymbol` | Currency symbol |
|
|
130
|
+
|
|
131
|
+
#### StoreItem
|
|
132
|
+
|
|
133
|
+
| Type | Property | Description |
|
|
134
|
+
|---------|------------------|---------------------------------------------------------------------------|
|
|
135
|
+
| String | `id` | Unique ID of the item in the store. |
|
|
136
|
+
| String | `name` | Name of the item. |
|
|
137
|
+
| String | `description?` | Description of the item. |
|
|
138
|
+
| Number | `price` | Price of the item. |
|
|
139
|
+
| Number | `stockRemaining` | Amount of stock remaining for the item. |
|
|
140
|
+
| Boolean | `unlimitedStock` | Whether the item has unlimited stock. |
|
|
141
|
+
| Boolean | `isInventory` | Indicates if the item will be added to a user’s inventory when purchased. |
|
|
142
|
+
| Date | `expiresAt?` | Expiration date of the item. |
|
|
143
|
+
| Boolean | `isUsable` | Whether the item can be used by the user. |
|
|
144
|
+
| Boolean | `isSellable` | Whether the item can be sold by the user. |
|
|
145
|
+
| Array | `requirements` | Requirements needed to purchase the item. |
|
|
146
|
+
| Array | `actions` | Actions performed when the item is used. |
|
|
147
|
+
| String | `emojiUnicode?` | Unicode emoji associated with the item. |
|
|
148
|
+
| String | `emojiId?` | Custom emoji ID associated with the item. |
|
|
149
|
+
|
|
150
|
+
#### InventoryItem
|
|
151
|
+
|
|
152
|
+
| Type | Property | Description |
|
|
153
|
+
|-------------------------------------------------|-----------------|-----------------------------------------------|
|
|
154
|
+
| String | `itemId` | Unique ID of the item in the inventory. |
|
|
155
|
+
| Number | `quantity` | Quantity of the item in the user's inventory. |
|
|
156
|
+
| String | `name` | Name of the item. |
|
|
157
|
+
| String | `description?` | Description of the item. |
|
|
158
|
+
| Boolean | `isUsable` | Whether the item can be used by the user. |
|
|
159
|
+
| Boolean | `isSellable` | Whether the item can be sold by the user. |
|
|
160
|
+
| [StoreItemRequirement[]](#StoreItemRequirement) | `requirements` | Requirements needed to use the item. |
|
|
161
|
+
| [StoreItemAction[]](#StoreItemAction) | `actions` | Actions performed when the item is used. |
|
|
162
|
+
| String | `emojiUnicode?` | Unicode emoji associated with the item. |
|
|
163
|
+
| String | `emojiId?` | Custom emoji ID associated with the item. |
|
|
164
|
+
|
|
165
|
+
#### StoreItemRequirement
|
|
166
|
+
|
|
167
|
+
| Type | Property | Description |
|
|
168
|
+
|-------------------------------|-------------|---------------------------------------------------------------------------------------|
|
|
169
|
+
| StoreItemRequirementType | `type` | Type of requirement. Could be one of `ROLE`, `TOTAL_BALANCE`, or `ITEM`. |
|
|
170
|
+
| StoreItemRequirementMatchType | `matchType` | Specifies how the requirement must be met. Can be `EVERY`, `AT_LEAST_ONE`, or `NONE`. |
|
|
171
|
+
| String[] | `ids` | An array of IDs that correspond to roles, items, or other required entities. |
|
|
172
|
+
| Number | `balance` | Minimum balance required (applicable if `type` is `TOTAL_BALANCE`). |
|
|
173
|
+
|
|
174
|
+
#### StoreItemAction
|
|
175
|
+
|
|
176
|
+
| Type | Property | Description |
|
|
177
|
+
|---------------------|------------|------------------------------------------------------------------------------------------------------------------------------------------|
|
|
178
|
+
| StoreItemActionType | `type` | Type of action. Could be one of `RESPOND`, `ADD_ROLES`, `REMOVE_ROLES`, `ADD_BALANCE`, `REMOVE_BALANCE`, `ADD_ITEMS`, or `REMOVE_ITEMS`. |
|
|
179
|
+
| String[] | `ids` | An array of IDs corresponding to roles, items, or other entities involved in the action. |
|
|
180
|
+
| Object | `message?` | Discord message object, only applicable if `type` is `RESPOND`. |
|
|
181
|
+
| Number | `balance?` | Balance amount to be added or removed (applicable if `type` is `ADD_BALANCE` or `REMOVE_BALANCE`). |
|
|
99
182
|
|
|
100
183
|
#### Permission
|
|
101
|
-
Type | Property | Description
|
|
102
|
-
--- | --- | ---
|
|
103
|
-
Number | `allow` | The allowed bitwise permissions number.
|
|
104
|
-
String | `json` | JSON representation of the allowed and denied permissions.
|
|
105
184
|
|
|
185
|
+
| Type | Property | Description |
|
|
186
|
+
|--------|----------|------------------------------------------------------------|
|
|
187
|
+
| Number | `allow` | The allowed bitwise permissions number. |
|
|
188
|
+
| String | `json` | JSON representation of the allowed and denied permissions. |
|
|
106
189
|
|
|
107
190
|
## Support
|
|
108
|
-
|
|
191
|
+
|
|
192
|
+
[**Discord Server**](https://discord.gg/unb)
|
package/index.d.ts
CHANGED
|
@@ -15,23 +15,25 @@ declare module 'unb-api' {
|
|
|
15
15
|
|
|
16
16
|
public editUserBalance(guildId: string, userId: string, balance: Balance, reason?: string): Promise<User>;
|
|
17
17
|
|
|
18
|
-
public getGuildLeaderboard(guildId: string, query?:
|
|
18
|
+
public getGuildLeaderboard(guildId: string, query?: ListOptions): Promise<User[]> | Promise<{ users: User[], totalPages: number }>;
|
|
19
19
|
|
|
20
20
|
public getGuild(guildId: string): Promise<Guild>;
|
|
21
21
|
|
|
22
22
|
public getApplicationPermission(guildId: string): Promise<Permission>;
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
public getItems(guildId: string, options?:
|
|
25
|
+
public getItems(guildId: string, options?: ListOptions): Promise<{ page: number, totalPages: number, items: StoreItem[] }>
|
|
26
26
|
|
|
27
27
|
public getItem(guildId: string, itemId: string): Promise<StoreItem>
|
|
28
|
+
|
|
29
|
+
public createItem(guildId: string): Promise<StoreItem>
|
|
28
30
|
|
|
29
31
|
public editItem(guildId: string, itemId: string, data: StoreItem | object, options?: { cascadeUpdate?: boolean }): Promise<StoreItem>
|
|
30
32
|
|
|
31
33
|
public deleteItem(guildId: string, itemId: string): Promise<any>
|
|
32
34
|
|
|
33
35
|
|
|
34
|
-
public getInventoryItems(guildId: string, userId: string, options?:
|
|
36
|
+
public getInventoryItems(guildId: string, userId: string, options?: ListOptions): Promise<{ page: number, totalPages: number, items: InventoryItem[] }>
|
|
35
37
|
|
|
36
38
|
public getInventoryItem(guildId: string, userId: string, itemId: string): Promise<InventoryItem>
|
|
37
39
|
|
|
@@ -157,10 +159,10 @@ declare module 'unb-api' {
|
|
|
157
159
|
balance: number;
|
|
158
160
|
}
|
|
159
161
|
|
|
160
|
-
export type
|
|
161
|
-
limit
|
|
162
|
-
page
|
|
163
|
-
sort
|
|
164
|
-
query
|
|
162
|
+
export type ListOptions = {
|
|
163
|
+
limit?: number;
|
|
164
|
+
page?: number;
|
|
165
|
+
sort?: string[] | string
|
|
166
|
+
query?: string;
|
|
165
167
|
}
|
|
166
168
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unb-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "API wrapper for UnbelievaBoat Discord Bot API",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -22,6 +22,6 @@
|
|
|
22
22
|
"typescript": "^2.6.2"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"axios": "
|
|
25
|
+
"axios": "1.6.0"
|
|
26
26
|
}
|
|
27
27
|
}
|
package/src/lib/Client.js
CHANGED
|
@@ -221,6 +221,23 @@ class Client {
|
|
|
221
221
|
.then(data => new StoreItem(data));
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Create an item
|
|
226
|
+
*
|
|
227
|
+
* @public
|
|
228
|
+
* @param {string} guildId - Guild ID
|
|
229
|
+
* @param {StoreItem|object} data - Item properties to create the item with
|
|
230
|
+
* @returns {Promise<StoreItem>}
|
|
231
|
+
*
|
|
232
|
+
* @see {@link https://unbelievaboat-api.readme.io/reference/create-store-item|Create Store Item}
|
|
233
|
+
*/
|
|
234
|
+
createItem(guildId, data) {
|
|
235
|
+
if (typeof guildId !== 'string') throw new TypeError('guildId must be a string');
|
|
236
|
+
|
|
237
|
+
return this._request('POST', `guilds/${guildId}/items`, toSnakeCaseDeep(data))
|
|
238
|
+
.then(data => new StoreItem(data));
|
|
239
|
+
}
|
|
240
|
+
|
|
224
241
|
/**
|
|
225
242
|
* Edit an item
|
|
226
243
|
*
|
|
@@ -231,6 +248,8 @@ class Client {
|
|
|
231
248
|
* @param [options]
|
|
232
249
|
* @param [options.cascadeUpdate=false] - Inventory items will also be updated if set to true
|
|
233
250
|
* @returns {Promise<StoreItem>}
|
|
251
|
+
*
|
|
252
|
+
* @see {@link https://unbelievaboat-api.readme.io/reference/edit-store-item|Edit Store Item}
|
|
234
253
|
*/
|
|
235
254
|
editItem(guildId, itemId, data, options) {
|
|
236
255
|
if (typeof guildId !== 'string') throw new TypeError('guildId must be a string');
|
|
@@ -248,6 +267,8 @@ class Client {
|
|
|
248
267
|
* @param {object} [options]
|
|
249
268
|
* @param {boolean} [options.cascadeDelete=false] - Inventory items will also be deleted if set to true
|
|
250
269
|
* @returns {Promise<*>}
|
|
270
|
+
*
|
|
271
|
+
* @see {@link https://unbelievaboat-api.readme.io/reference/delete-store-item|Delete Store Item}
|
|
251
272
|
*/
|
|
252
273
|
deleteItem(guildId, itemId, options) {
|
|
253
274
|
if (typeof guildId !== 'string') throw new TypeError('guildId must be a string');
|
|
@@ -268,6 +289,8 @@ class Client {
|
|
|
268
289
|
* @param {number} [options.limit=100] - Maximum number of items to return
|
|
269
290
|
* @param {string} [options.query] - Search for an item by name
|
|
270
291
|
* @returns {Promise<{totalPages: number, page: number, items: InventoryItem[]}>}
|
|
292
|
+
*
|
|
293
|
+
* @see {@link https://unbelievaboat-api.readme.io/reference/get-user-inventory-items|Get Inventory Items}
|
|
271
294
|
*/
|
|
272
295
|
getInventoryItems(guildId, userId, options) {
|
|
273
296
|
if (typeof guildId !== 'string') throw new TypeError('guildId must be a string');
|
|
@@ -290,7 +313,9 @@ class Client {
|
|
|
290
313
|
* @param {string} guildId - Guild ID
|
|
291
314
|
* @param {string} userId - User ID
|
|
292
315
|
* @param {string} itemId - Item ID
|
|
293
|
-
* @returns {Promise<
|
|
316
|
+
* @returns {Promise<InventoryItem>}
|
|
317
|
+
*
|
|
318
|
+
* @see {@link https://unbelievaboat-api.readme.io/reference/get-inventory-item|Get Inventory Item}
|
|
294
319
|
*/
|
|
295
320
|
getInventoryItem(guildId, userId, itemId) {
|
|
296
321
|
if (typeof guildId !== 'string') throw new TypeError('guildId must be a string');
|
|
@@ -312,6 +337,8 @@ class Client {
|
|
|
312
337
|
* @param {object} [options]
|
|
313
338
|
* @param {string} [options.inventoryUserId] - User ID of the inventory to add the item from (can be used if the item no longer exists in the store or the item settings differ)
|
|
314
339
|
* @returns {Promise<InventoryItem>}
|
|
340
|
+
*
|
|
341
|
+
* @see {@link https://unbelievaboat-api.readme.io/reference/add-inventory-item|Add Inventory Item}
|
|
315
342
|
*/
|
|
316
343
|
addInventoryItem(guildId, userId, itemId, quantity, options) {
|
|
317
344
|
if (typeof guildId !== 'string') throw new TypeError('guildId must be a string');
|
|
@@ -331,6 +358,8 @@ class Client {
|
|
|
331
358
|
* @param {string} itemId - Item ID
|
|
332
359
|
* @param {number|string} [quantity=1] - Quantity to remove
|
|
333
360
|
* @returns {Promise<*>}
|
|
361
|
+
*
|
|
362
|
+
* @see {@link https://unbelievaboat-api.readme.io/reference/remove-inventory-item|Remove Inventory Item}
|
|
334
363
|
*/
|
|
335
364
|
removeInventoryItem(guildId, userId, itemId, quantity) {
|
|
336
365
|
if (typeof guildId !== 'string') throw new TypeError('guildId must be a string');
|
|
@@ -7,85 +7,86 @@ class RequestHandler {
|
|
|
7
7
|
constructor(client) {
|
|
8
8
|
this._client = client;
|
|
9
9
|
this.ratelimits = {};
|
|
10
|
+
this.axiosInstance = axios.create({
|
|
11
|
+
baseURL: this._client.baseURL,
|
|
12
|
+
headers: {
|
|
13
|
+
'Authorization': this._client.token,
|
|
14
|
+
'Content-Type': 'application/json'
|
|
15
|
+
}
|
|
16
|
+
});
|
|
10
17
|
}
|
|
11
18
|
|
|
12
|
-
request(method, endpoint, data = {},
|
|
19
|
+
async request(method, endpoint, data = {}, params = {}, _attempts = 0) {
|
|
13
20
|
const route = this.getRoute(method, endpoint);
|
|
14
21
|
if (!this.ratelimits[route]) {
|
|
15
22
|
this.ratelimits[route] = new Bucket();
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
return new Promise((resolve, reject) => {
|
|
19
|
-
const fn = (callback) => {
|
|
26
|
+
const fn = async (callback) => {
|
|
20
27
|
const options = {
|
|
21
|
-
|
|
22
|
-
headers: {
|
|
23
|
-
'Authorization': this._client.token,
|
|
24
|
-
'Content-Type': 'application/json'
|
|
25
|
-
},
|
|
26
|
-
baseURL: this._client.baseURL,
|
|
28
|
+
method,
|
|
27
29
|
url: `/${this._client.version ? `${this._client.version}/` : ''}${endpoint}`,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
params: query
|
|
30
|
+
data,
|
|
31
|
+
params,
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const retryRequest = () => {
|
|
51
|
-
// Use the retry-after header to schedule the request to retry
|
|
52
|
-
if (res.headers['retry-after']) {
|
|
53
|
-
setTimeout(() => {
|
|
54
|
-
this.request(method, endpoint, data, query, _attempts)
|
|
55
|
-
.then(resolve)
|
|
56
|
-
.catch(reject);
|
|
57
|
-
}, +res.headers['retry-after']);
|
|
58
|
-
} else {
|
|
59
|
-
// Retry immediately if no retry-after header
|
|
60
|
-
this.request(method, endpoint, data, query, _attempts)
|
|
61
|
-
.then(resolve)
|
|
62
|
-
.catch(reject);
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
if (res.status >= 200 && res.status < 300) {
|
|
67
|
-
resolve(res.data);
|
|
68
|
-
} else if (res.status === 429) {
|
|
69
|
-
// Check if too many retry attempts
|
|
70
|
-
if (_attempts >= this._client.maxRetries) {
|
|
71
|
-
rejectWithError();
|
|
72
|
-
} else {
|
|
73
|
-
retryRequest();
|
|
74
|
-
}
|
|
34
|
+
try {
|
|
35
|
+
const { data: responseData, status, headers } = await this.axiosInstance(options);
|
|
36
|
+
|
|
37
|
+
// Increase the number of attempts
|
|
38
|
+
++_attempts;
|
|
39
|
+
|
|
40
|
+
// Add the rate limit header data to the bucket
|
|
41
|
+
this.parseRateLimitHeaders(route, headers);
|
|
42
|
+
|
|
43
|
+
if (status >= 200 && status < 300) {
|
|
44
|
+
resolve(responseData);
|
|
45
|
+
} else if (status === 429) {
|
|
46
|
+
if (_attempts >= this._client.maxRetries) {
|
|
47
|
+
this.rejectWithError(options, responseData, status, reject);
|
|
75
48
|
} else {
|
|
76
|
-
|
|
49
|
+
this.retryRequest(method, endpoint, data, params, _attempts, headers, resolve, reject);
|
|
77
50
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
51
|
+
} else {
|
|
52
|
+
this.rejectWithError(options, responseData, status, reject);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
callback();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (axios.isAxiosError(error)) {
|
|
58
|
+
this.rejectWithError(options, error.response.data, error.response.status, reject);
|
|
59
|
+
} else {
|
|
60
|
+
reject(error);
|
|
61
|
+
}
|
|
62
|
+
callback();
|
|
63
|
+
}
|
|
81
64
|
};
|
|
82
65
|
|
|
83
66
|
this.ratelimits[route].queue(fn);
|
|
84
67
|
});
|
|
85
68
|
}
|
|
86
69
|
|
|
70
|
+
rejectWithError(options, data, status, reject) {
|
|
71
|
+
if (data && data.message) {
|
|
72
|
+
reject(new APIError(options, { data, status }));
|
|
73
|
+
} else {
|
|
74
|
+
reject(new HTTPError(options, { data, status }));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
retryRequest(method, endpoint, data, params, _attempts, headers, resolve, reject) {
|
|
79
|
+
const retryAfter = headers['retry-after'] ? +headers['retry-after'] : 0;
|
|
80
|
+
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
this.request(method, endpoint, data, params, _attempts)
|
|
83
|
+
.then(resolve)
|
|
84
|
+
.catch(reject);
|
|
85
|
+
}, retryAfter);
|
|
86
|
+
}
|
|
87
|
+
|
|
87
88
|
getRoute(method, endpoint) {
|
|
88
|
-
const route = endpoint.replace(/\/([a-z-]+)\/(
|
|
89
|
+
const route = endpoint.replace(/\/([a-z-]+)\/(\d+)/g, (match, p) => {
|
|
89
90
|
return MajorParams.includes(p) ? match : `/${p}/:id`;
|
|
90
91
|
});
|
|
91
92
|
return `${method}/${route}`;
|
|
@@ -111,7 +112,6 @@ class RequestHandler {
|
|
|
111
112
|
} else {
|
|
112
113
|
this.ratelimits[route].reset = now;
|
|
113
114
|
}
|
|
114
|
-
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
constructor(response) {
|
|
3
|
-
super();
|
|
4
|
-
this.name = this.constructor.name;
|
|
5
|
-
this.message = response.data.error || response.data.message || 'Unknown error';
|
|
6
|
-
this.status = response.status;
|
|
7
|
-
this.errors = response.data.errors || null;
|
|
1
|
+
const HTTPError = require('./HTTPError');
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
class APIError extends HTTPError {
|
|
4
|
+
constructor(request, response) {
|
|
5
|
+
super(request, response);
|
|
6
|
+
this.message = response.data.message || response.data.error || response.statusText || 'Unknown error';
|
|
7
|
+
this.errors = response.data.errors || null;
|
|
13
8
|
}
|
|
14
9
|
}
|
|
15
10
|
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
class HTTPError extends Error {
|
|
2
|
-
constructor(response) {
|
|
2
|
+
constructor(request, response) {
|
|
3
3
|
super();
|
|
4
4
|
this.name = this.constructor.name;
|
|
5
5
|
this.message = response.statusText || 'Unknown error';
|
|
6
6
|
this.status = response.status;
|
|
7
7
|
|
|
8
|
+
Object.defineProperty(this, 'request', {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
value: request
|
|
11
|
+
});
|
|
12
|
+
|
|
8
13
|
Object.defineProperty(this, 'response', {
|
|
9
14
|
enumerable: true,
|
|
10
15
|
value: response
|