noblox.ts 4.10.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of noblox.ts might be problematic. Click here for more details.
- package/.eslintrc.js +21 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- package/.github/workflows/doc-publish.yml +33 -0
- package/.github/workflows/npmpublish.yml +70 -0
- package/.travis.yml +13 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/examples/cleanPlayers.js +130 -0
- package/examples/cleanWall.js +110 -0
- package/examples/revertRanks.js +100 -0
- package/examples/savePlayers.js +119 -0
- package/examples/saveWall.js +96 -0
- package/img/moderatedThumbnails/moderatedThumbnail_100x100.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_110x110.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_140x140.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_150x150.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_150x200.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_180x180.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_250x250.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_30x30.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_352x352.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_420x420.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_48x48.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_50x50.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_60x60.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_720x720.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_75x75.png +0 -0
- package/img/noblox-js-small.png +0 -0
- package/img/noblox-js.png +0 -0
- package/img/thumbnailSizes.png +0 -0
- package/jsDocsConfig.json +55 -0
- package/lib/accountinformation/getUserSocialLinks.js +42 -0
- package/lib/accountsettings/block.js +58 -0
- package/lib/accountsettings/unblock.js +58 -0
- package/lib/asset/deleteFromInventory.js +69 -0
- package/lib/asset/getGamePassProductInfo.js +51 -0
- package/lib/asset/getProductInfo.js +56 -0
- package/lib/asset/uploadAnimation.js +103 -0
- package/lib/asset/uploadItem.js +83 -0
- package/lib/asset/uploadModel.js +90 -0
- package/lib/avatar/avatarRules.js +38 -0
- package/lib/avatar/currentlyWearing.js +32 -0
- package/lib/avatar/getAvatar.js +35 -0
- package/lib/avatar/getCurrentAvatar.js +37 -0
- package/lib/avatar/getRecentItems.js +37 -0
- package/lib/avatar/outfitDetails.js +32 -0
- package/lib/avatar/outfits.js +37 -0
- package/lib/avatar/redrawAvatar.js +48 -0
- package/lib/avatar/removeAssetId.js +55 -0
- package/lib/avatar/setAvatarBodyColors.js +60 -0
- package/lib/avatar/setAvatarScales.js +60 -0
- package/lib/avatar/setPlayerAvatarType.js +50 -0
- package/lib/avatar/setWearingAssets.js +50 -0
- package/lib/avatar/wearAssetId.js +55 -0
- package/lib/badges/getAwardedTimestamps.js +52 -0
- package/lib/badges/getBadgeInfo.js +43 -0
- package/lib/badges/getGameBadges.js +62 -0
- package/lib/badges/getPlayerBadges.js +28 -0
- package/lib/badges/updateBadgeInfo.js +80 -0
- package/lib/cache/add.js +14 -0
- package/lib/cache/addIf.js +26 -0
- package/lib/cache/clear.js +8 -0
- package/lib/cache/get.js +28 -0
- package/lib/cache/index.js +17 -0
- package/lib/cache/new.js +12 -0
- package/lib/cache/wrap.js +25 -0
- package/lib/chat/addUsersToConversation.js +61 -0
- package/lib/chat/chatSettings.js +33 -0
- package/lib/chat/getChatMessages.js +40 -0
- package/lib/chat/getConversations.js +43 -0
- package/lib/chat/getRolloutSettings.js +35 -0
- package/lib/chat/getUnreadConversationCount.js +33 -0
- package/lib/chat/getUnreadMessages.js +38 -0
- package/lib/chat/getUserConversations.js +37 -0
- package/lib/chat/markChatAsRead.js +52 -0
- package/lib/chat/markChatAsSeen.js +50 -0
- package/lib/chat/multiGetLatestMessages.js +37 -0
- package/lib/chat/onNewConversation.js +50 -0
- package/lib/chat/onNewMessage.js +53 -0
- package/lib/chat/onNewMessageBySelf.js +50 -0
- package/lib/chat/onUserOnline.js +50 -0
- package/lib/chat/onUserTyping.js +54 -0
- package/lib/chat/removeFromGroupConversation.js +62 -0
- package/lib/chat/renameGroupConversation.js +57 -0
- package/lib/chat/sendChatMessage.js +57 -0
- package/lib/chat/setChatUserTyping.js +61 -0
- package/lib/chat/start121Conversation.js +50 -0
- package/lib/chat/startCloudEditConversation.js +50 -0
- package/lib/chat/startGroupConversation.js +62 -0
- package/lib/client/onNotification.js +70 -0
- package/lib/client/setAPIKey.js +18 -0
- package/lib/client/setCookie.js +38 -0
- package/lib/datastores/deleteDatastoreEntry.js +66 -0
- package/lib/datastores/getDatastoreEntry.js +98 -0
- package/lib/datastores/getDatastoreEntryVersions.js +83 -0
- package/lib/datastores/getDatastoreKeys.js +73 -0
- package/lib/datastores/getDatastores.js +72 -0
- package/lib/datastores/incrementDatastoreEntry.js +93 -0
- package/lib/datastores/setDatastoreEntry.js +90 -0
- package/lib/develop/canManage.js +44 -0
- package/lib/develop/configureItem.js +142 -0
- package/lib/develop/updateUniverse.js +53 -0
- package/lib/develop/updateUniverseAccess.js +55 -0
- package/lib/economy/buy.js +99 -0
- package/lib/economy/getGroupFunds.js +43 -0
- package/lib/economy/getGroupRevenueSummary.js +48 -0
- package/lib/economy/getGroupTransactions.js +32 -0
- package/lib/economy/getResaleData.js +54 -0
- package/lib/economy/getResellers.js +35 -0
- package/lib/economy/getUserTransactions.js +34 -0
- package/lib/economy/onGroupTransaction.js +74 -0
- package/lib/friends/acceptFriendRequest.js +59 -0
- package/lib/friends/declineAllFriendRequests.js +57 -0
- package/lib/friends/declineFriendRequest.js +59 -0
- package/lib/friends/getFollowers.js +61 -0
- package/lib/friends/getFollowings.js +61 -0
- package/lib/friends/getFriendRequests.js +56 -0
- package/lib/friends/getFriends.js +53 -0
- package/lib/friends/onFriendRequest.js +58 -0
- package/lib/friends/removeFriend.js +58 -0
- package/lib/friends/sendFriendRequest.js +59 -0
- package/lib/friends/unfollow.js +58 -0
- package/lib/games/addDeveloperProduct.js +65 -0
- package/lib/games/checkDeveloperProductName.js +39 -0
- package/lib/games/configureGamePass.js +146 -0
- package/lib/games/getDeveloperProducts.js +51 -0
- package/lib/games/getGameInstances.js +31 -0
- package/lib/games/getGamePasses.js +39 -0
- package/lib/games/getGameRevenue.js +49 -0
- package/lib/games/getGameSocialLinks.js +45 -0
- package/lib/games/getGroupGames.js +30 -0
- package/lib/games/getPlaceInfo.js +48 -0
- package/lib/games/getUniverseInfo.js +51 -0
- package/lib/games/updateDeveloperProduct.js +69 -0
- package/lib/groups/changeRank.js +59 -0
- package/lib/groups/deleteWallPost.js +64 -0
- package/lib/groups/deleteWallPostsByUser.js +59 -0
- package/lib/groups/demote.js +25 -0
- package/lib/groups/exile.js +59 -0
- package/lib/groups/getAuditLog.js +67 -0
- package/lib/groups/getGroup.js +57 -0
- package/lib/groups/getGroupSocialLinks.js +44 -0
- package/lib/groups/getGroups.js +88 -0
- package/lib/groups/getJoinRequest.js +52 -0
- package/lib/groups/getJoinRequests.js +58 -0
- package/lib/groups/getPlayers.js +108 -0
- package/lib/groups/getRankInGroup.js +52 -0
- package/lib/groups/getRankNameInGroup.js +52 -0
- package/lib/groups/getRole.js +64 -0
- package/lib/groups/getRolePermissions.js +51 -0
- package/lib/groups/getRoles.js +56 -0
- package/lib/groups/getShout.js +49 -0
- package/lib/groups/getWall.js +59 -0
- package/lib/groups/groupPayout.js +103 -0
- package/lib/groups/handleJoinRequest.js +60 -0
- package/lib/groups/leaveGroup.js +60 -0
- package/lib/groups/onAuditLog.js +62 -0
- package/lib/groups/onJoinRequest.js +63 -0
- package/lib/groups/onJoinRequestHandle.js +105 -0
- package/lib/groups/onShout.js +57 -0
- package/lib/groups/onWallPost.js +58 -0
- package/lib/groups/promote.js +25 -0
- package/lib/groups/searchGroups.js +32 -0
- package/lib/groups/setGroupDescription.js +65 -0
- package/lib/groups/setGroupName.js +66 -0
- package/lib/groups/setRank.js +79 -0
- package/lib/groups/shout.js +65 -0
- package/lib/index.js +30 -0
- package/lib/internal/levelOneCopy.js +16 -0
- package/lib/internal/queue.js +61 -0
- package/lib/internal/timeout.js +30 -0
- package/lib/internal/wrap.js +78 -0
- package/lib/inventory/getCollectibles.js +31 -0
- package/lib/inventory/getInventory.js +32 -0
- package/lib/inventory/getInventoryById.js +31 -0
- package/lib/inventory/getOwnership.js +54 -0
- package/lib/inventory/getUAIDs.js +47 -0
- package/lib/itemconfiguration/getGroupAssets.js +32 -0
- package/lib/options.js +26 -0
- package/lib/party/onPartyDeleted.js +53 -0
- package/lib/party/onPartyInvite.js +53 -0
- package/lib/party/onPartyJoinedGame.js +53 -0
- package/lib/party/onPartyLeftGame.js +53 -0
- package/lib/party/onPartySelfJoined.js +53 -0
- package/lib/party/onPartySelfLeft.js +53 -0
- package/lib/party/onPartyUserJoined.js +53 -0
- package/lib/party/onPartyUserLeft.js +53 -0
- package/lib/premiumfeatures/getPremium.js +51 -0
- package/lib/presence/getPresences.js +63 -0
- package/lib/privatemessages/getMessages.js +60 -0
- package/lib/privatemessages/message.js +80 -0
- package/lib/privatemessages/onMessage.js +88 -0
- package/lib/thumbnails/getLogo.js +60 -0
- package/lib/thumbnails/getPlayerThumbnail.js +121 -0
- package/lib/thumbnails/getThumbnails.js +93 -0
- package/lib/trades/acceptTrade.js +58 -0
- package/lib/trades/canTradeWith.js +48 -0
- package/lib/trades/counterTrade.js +84 -0
- package/lib/trades/declineTrade.js +58 -0
- package/lib/trades/getTradeInfo.js +52 -0
- package/lib/trades/getTrades.js +37 -0
- package/lib/trades/sendTrade.js +82 -0
- package/lib/users/getBlurb.js +36 -0
- package/lib/users/getIdFromUsername.js +53 -0
- package/lib/users/getPlayerInfo.js +100 -0
- package/lib/users/getUsernameFromId.js +44 -0
- package/lib/users/onBlurbChange.js +46 -0
- package/lib/util/clearSession.js +32 -0
- package/lib/util/generalRequest.js +61 -0
- package/lib/util/getAction.js +45 -0
- package/lib/util/getCurrentUser.js +44 -0
- package/lib/util/getGeneralToken.js +52 -0
- package/lib/util/getHash.js +29 -0
- package/lib/util/getInputs.js +37 -0
- package/lib/util/getPageResults.js +89 -0
- package/lib/util/getSenderUserId.js +30 -0
- package/lib/util/getSession.js +38 -0
- package/lib/util/getVerification.js +60 -0
- package/lib/util/getVerificationInputs.js +31 -0
- package/lib/util/http.js +110 -0
- package/lib/util/jar.js +24 -0
- package/lib/util/refreshCookie.js +52 -0
- package/lib/util/relog.js +81 -0
- package/lib/util/setOptions.js +54 -0
- package/lib/util/shortPoll.js +102 -0
- package/lib/util/threaded.js +80 -0
- package/package.json +94 -0
- package/postinstall.js +1 -0
- package/settings.json +107 -0
- package/test/accountinformation.test.js +27 -0
- package/test/accountsettings.test.js +27 -0
- package/test/asset.test.js +81 -0
- package/test/assets/Great-White-Shark-Fin.rbxm +0 -0
- package/test/assets/KeyframeSequence.rbxm +0 -0
- package/test/avatar.test.js +164 -0
- package/test/badges.test.js +96 -0
- package/test/chat.test.js +104 -0
- package/test/datastore.test.js +105 -0
- package/test/develop.test.js +53 -0
- package/test/economy.test.js +137 -0
- package/test/friends.test.js +128 -0
- package/test/games.test.js +212 -0
- package/test/groups.test.js +311 -0
- package/test/inventory.test.js +98 -0
- package/test/itemconfiguration.test.js +24 -0
- package/test/premiumfeatures.test.js +17 -0
- package/test/presence.test.js +25 -0
- package/test/privatemessages.test.js +33 -0
- package/test/thumbnails.test.js +53 -0
- package/test/users.test.js +68 -0
- package/tutorials/Authentication.md +75 -0
- package/tutorials/Event Emitters.md +26 -0
- package/tutorials/Promises.md +86 -0
- package/tutorials/VPS Authentication.md +72 -0
- package/typings/index.d.ts +2525 -0
- package/typings/jsDocs.ts +1927 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('../util/http.js').func
|
3
|
+
|
4
|
+
// Args
|
5
|
+
exports.required = ['group']
|
6
|
+
exports.optional = ['size', 'circular', 'format']
|
7
|
+
|
8
|
+
// Docs
|
9
|
+
/**
|
10
|
+
* ✅ Get the group's logo.
|
11
|
+
* @category Group
|
12
|
+
* @alias getLogo
|
13
|
+
* @param {number} group - The id of the group.
|
14
|
+
* @param {GroupIconSize=} [size=150x150] - The size of the logo.
|
15
|
+
* @param {boolean=} [circular=false] - Get the circular version of the logo.
|
16
|
+
* @param {GroupIconFormat=} [format=Png] - The file format of the logo.
|
17
|
+
* @returns {Promise<string>}
|
18
|
+
* @example const noblox = require("noblox.js")
|
19
|
+
* const logo = await noblox.getLogo(1)
|
20
|
+
**/
|
21
|
+
|
22
|
+
// Define
|
23
|
+
function getLogo (group, size, circular, format) {
|
24
|
+
const httpOpt = {
|
25
|
+
url: '//thumbnails.roblox.com/v1/groups/icons',
|
26
|
+
options: {
|
27
|
+
qs: {
|
28
|
+
groupIds: group,
|
29
|
+
size: size || '150x150',
|
30
|
+
format: format || 'Png',
|
31
|
+
isCircular: circular
|
32
|
+
},
|
33
|
+
json: true
|
34
|
+
}
|
35
|
+
}
|
36
|
+
return http(httpOpt)
|
37
|
+
.then(function (body) {
|
38
|
+
const error = body.errors && body.errors[0]
|
39
|
+
|
40
|
+
if (error) {
|
41
|
+
if (error.message === 'NotFound') {
|
42
|
+
throw new Error('An invalid UserID or GroupID was provided.')
|
43
|
+
} else {
|
44
|
+
throw new Error(error.message)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
const thumbnailData = body.data[0]
|
49
|
+
|
50
|
+
if (thumbnailData.state !== 'Completed') {
|
51
|
+
throw new Error('The requested image has not been approved. Status: ' + thumbnailData.state)
|
52
|
+
}
|
53
|
+
|
54
|
+
return thumbnailData.imageUrl
|
55
|
+
})
|
56
|
+
}
|
57
|
+
|
58
|
+
exports.func = function (args) {
|
59
|
+
return getLogo(args.group)
|
60
|
+
}
|
@@ -0,0 +1,121 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('../util/http.js').func
|
3
|
+
const { thumbnail: settings } = require('../../settings.json')
|
4
|
+
|
5
|
+
// Args
|
6
|
+
exports.required = ['userIds']
|
7
|
+
exports.optional = ['size', 'format', 'isCircular', 'cropType', 'retryCount']
|
8
|
+
|
9
|
+
// Variables
|
10
|
+
const eligibleSizes = {
|
11
|
+
body: {
|
12
|
+
sizes: ['30x30', '48x48', '60x60', '75x75', '100x100', '110x110', '140x140', '150x150', '150x200', '180x180', '250x250', '352x352', '420x420', '720x720'],
|
13
|
+
endpoint: 'avatar'
|
14
|
+
},
|
15
|
+
bust: {
|
16
|
+
sizes: ['48x48', '50x50', '60x60', '75x75', '100x100', '150x150', '180x180', '352x352', '420x420'],
|
17
|
+
endpoint: 'avatar-bust'
|
18
|
+
},
|
19
|
+
headshot: {
|
20
|
+
sizes: ['48x48', '50x50', '60x60', '75x75', '100x100', '110x110', '150x150', '180x180', '352x352', '420x420', '720x720'],
|
21
|
+
endpoint: 'avatar-headshot'
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
// Docs
|
26
|
+
/**
|
27
|
+
* ✅ Get a user's thumbnail.
|
28
|
+
* @category User
|
29
|
+
* @alias getPlayerThumbnail
|
30
|
+
* @param {number | Array<number>} userIds - The id or an array ids of thumbnails to be retrieved; 100
|
31
|
+
* @param {number | string=} [size=720x720] - The [size of the image to be returned]{@link https://noblox.js.org/thumbnailSizes.png}; defaults highest resolution
|
32
|
+
* @param {'png' | 'jpeg'=} [format=png] - The file format of the returned thumbnails
|
33
|
+
* @param {boolean=} [isCircular=false] - Return the circular version of the thumbnails
|
34
|
+
* @param {'Body' | 'Bust' | 'Headshot'=} [cropType=Body] - The style of thumbnail that will be returned
|
35
|
+
* @returns {Promise<PlayerThumbnailData[]>}
|
36
|
+
* @example const noblox = require("noblox.js")
|
37
|
+
* let thumbnail_default = await noblox.getPlayerThumbnail(2416399685)
|
38
|
+
* let thumbnail_circHeadshot = await noblox.getPlayerThumbnail(2416399685, 420, "png", true, "Headshot")
|
39
|
+
* let thumbnails_body = await noblox.getPlayerThumbnail([2416399685, 234567, 345678], "150x200", "jpeg", false, "Body")
|
40
|
+
**/
|
41
|
+
|
42
|
+
// Define
|
43
|
+
function getPlayerThumbnail (userIds, size, format = 'png', isCircular = false, cropType = 'body', retryCount = settings.maxRetries) {
|
44
|
+
// Validate userIds
|
45
|
+
if (Array.isArray(userIds)) {
|
46
|
+
if (userIds.some(isNaN)) {
|
47
|
+
throw new Error('userIds must be a number or an array of numbers')
|
48
|
+
}
|
49
|
+
userIds = [...new Set(userIds)] // get rid of duplicates, endpoint response does this anyway
|
50
|
+
if (userIds.length > 100) {
|
51
|
+
throw new Error(`too many userIds provided (${userIds.length}); maximum 100`)
|
52
|
+
}
|
53
|
+
} else {
|
54
|
+
if (isNaN(userIds)) {
|
55
|
+
throw new Error('userId is not a number')
|
56
|
+
}
|
57
|
+
userIds = [userIds]
|
58
|
+
}
|
59
|
+
|
60
|
+
// Validate cropType
|
61
|
+
cropType = cropType.toLowerCase()
|
62
|
+
if (!Object.keys(eligibleSizes).includes(cropType)) {
|
63
|
+
throw new Error(`Invalid cropping type provided: ${cropType} | Use: ${Object.keys(eligibleSizes).join(', ')}`)
|
64
|
+
}
|
65
|
+
const { sizes, endpoint } = eligibleSizes[cropType]
|
66
|
+
|
67
|
+
// Validate size
|
68
|
+
size = size || sizes[sizes.length - 1]
|
69
|
+
if (typeof size === 'number') {
|
70
|
+
size = `${size}x${size}`
|
71
|
+
}
|
72
|
+
if (!sizes.includes(size)) {
|
73
|
+
throw new Error(`Invalid size parameter provided: ${size} | [${cropType.toUpperCase()}] Use: ${sizes.join(', ')}`)
|
74
|
+
}
|
75
|
+
|
76
|
+
// Validate format
|
77
|
+
if (format.toLowerCase() !== 'png' && format.toLowerCase() !== 'jpeg') {
|
78
|
+
throw new Error(`Invalid image type provided: ${format} | Use: png, jpeg`)
|
79
|
+
}
|
80
|
+
|
81
|
+
return http({
|
82
|
+
url: `https://thumbnails.roblox.com/v1/users/${endpoint}?userIds=${userIds.join(',')}&size=${size}&format=${format}&isCircular=${!!isCircular}`,
|
83
|
+
options: {
|
84
|
+
resolveWithFullResponse: true,
|
85
|
+
followRedirect: true
|
86
|
+
}
|
87
|
+
})
|
88
|
+
.then(async ({ statusCode, body }) => {
|
89
|
+
let { data, errors } = JSON.parse(body)
|
90
|
+
if (statusCode === 200) {
|
91
|
+
if (retryCount > 0) {
|
92
|
+
const pendingThumbnails = data.filter(obj => { return obj.state === 'Pending' }).map(obj => obj.targetId) // Get 'Pending' thumbnails as array of userIds
|
93
|
+
if (pendingThumbnails.length > 0) {
|
94
|
+
await timeout(settings.retryDelay) // small delay helps cache populate on Roblox's end; default 500ms
|
95
|
+
const updatedPending = await getPlayerThumbnail(pendingThumbnails, size, format, isCircular, cropType, --retryCount) // Recursively retry for # of maxRetries attempts; default 2
|
96
|
+
data = data.map(obj => updatedPending.find(o => o.targetId === obj.targetId) || obj) // Update primary array's values
|
97
|
+
}
|
98
|
+
}
|
99
|
+
data = data.map(obj => {
|
100
|
+
if (obj.state !== 'Completed') {
|
101
|
+
const settingsUrl = settings.failedUrl[obj.state.toLowerCase()] // user defined settings.json default image URL for blocked or pending thumbnails; default ""
|
102
|
+
obj.imageUrl = settingsUrl || `https://noblox.js.org/moderatedThumbnails/moderatedThumbnail_${size}.png`
|
103
|
+
}
|
104
|
+
return obj
|
105
|
+
})
|
106
|
+
return data
|
107
|
+
} else if (statusCode === 400) {
|
108
|
+
throw new Error(`Error Code ${errors.code}: ${errors.message} | endpoint: ${endpoint}, userIds: ${userIds.join(',')}, size: ${size}, isCircular: ${!!isCircular}`)
|
109
|
+
} else {
|
110
|
+
throw new Error(`An unknown error occurred with getPlayerThumbnail() | endpoint: ${endpoint}, userIds: ${userIds.join(',')}, size: ${size}, isCircular: ${!!isCircular}`)
|
111
|
+
}
|
112
|
+
})
|
113
|
+
}
|
114
|
+
|
115
|
+
function timeout (ms) {
|
116
|
+
return new Promise(resolve => { setTimeout(resolve, ms) })
|
117
|
+
}
|
118
|
+
|
119
|
+
exports.func = function ({ userIds, size, format, isCircular, cropType, retryCount }) {
|
120
|
+
return getPlayerThumbnail(userIds, size, format, isCircular, cropType, retryCount)
|
121
|
+
}
|
@@ -0,0 +1,93 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('../util/http.js').func
|
3
|
+
const { thumbnail: settings } = require('../../settings.json')
|
4
|
+
|
5
|
+
// Args
|
6
|
+
exports.required = ['thumbnailRequests']
|
7
|
+
exports.optional = []
|
8
|
+
|
9
|
+
// Docs
|
10
|
+
/**
|
11
|
+
* ✅ Get thumbnails for assets/players.
|
12
|
+
* @category Assets
|
13
|
+
* @alias getThumbnails
|
14
|
+
* @param {Array<ThumbnailRequest>} thumbnailRequests - The id or an array ids of thumbnails to be retrieved; 100
|
15
|
+
* @returns {Promise<ThumbnailData[]>}
|
16
|
+
* @example const noblox = require("noblox.js")
|
17
|
+
* const playerThumbnails = noblox.getThumbnails([
|
18
|
+
* {
|
19
|
+
* type: "AvatarHeadShot",
|
20
|
+
* token: "270FF19ECB1AFCF25383A6F37C6AD307",
|
21
|
+
* format: "png",
|
22
|
+
* size: "150x150"
|
23
|
+
* }, {
|
24
|
+
* type: "AvatarBust",
|
25
|
+
* targetId: 55549140,
|
26
|
+
* isCircular: true,
|
27
|
+
* format: "png",
|
28
|
+
* size: "150x150"
|
29
|
+
* }
|
30
|
+
* ])
|
31
|
+
**/
|
32
|
+
|
33
|
+
// Define
|
34
|
+
function getThumbnails (requests, retryCount = settings.maxRetries) {
|
35
|
+
if (!Array.isArray(requests)) {
|
36
|
+
throw new Error('thumbnailRequests are not an array')
|
37
|
+
}
|
38
|
+
|
39
|
+
requests = [...new Set(requests)]
|
40
|
+
if (requests.length > 100) {
|
41
|
+
throw new Error(`Too many thumbnailRequests provided (${requests.length}); maximum 100`)
|
42
|
+
}
|
43
|
+
|
44
|
+
for (const request of requests) {
|
45
|
+
if (!request.size || !request.type) {
|
46
|
+
throw new Error('thumbnailRequest must have a size and type')
|
47
|
+
} else if (request.format && (request.format.toLowerCase() !== 'png' && request.format.toLowerCase() !== 'jpeg')) {
|
48
|
+
throw new Error(`Invalid image type provided: ${request.format} | Use: png, jpeg`)
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
return http({
|
53
|
+
url: 'https://thumbnails.roblox.com/v1/batch',
|
54
|
+
options: {
|
55
|
+
method: 'POST',
|
56
|
+
json: requests,
|
57
|
+
resolveWithFullResponse: true,
|
58
|
+
followRedirect: true
|
59
|
+
}
|
60
|
+
})
|
61
|
+
.then(async ({ statusCode, body }) => {
|
62
|
+
let { data, errors } = body
|
63
|
+
if (statusCode === 200) {
|
64
|
+
if (retryCount > 0) {
|
65
|
+
const pendingThumbnails = data.filter(obj => { return obj.state === 'Pending' }).map(obj => obj.targetId) // Get 'Pending' thumbnails as array of userIds
|
66
|
+
if (pendingThumbnails.length > 0) {
|
67
|
+
await timeout(settings.retryDelay) // small delay helps cache populate on Roblox's end; default 500ms
|
68
|
+
const updatedPending = await getThumbnails(pendingThumbnails, --retryCount) // Recursively retry for # of maxRetries attempts; default 2
|
69
|
+
data = data.map(obj => updatedPending.find(o => o.targetId === obj.targetId) || obj) // Update primary array's values
|
70
|
+
}
|
71
|
+
}
|
72
|
+
data = data.map(obj => {
|
73
|
+
if (obj.state !== 'Completed') {
|
74
|
+
obj.imageUrl = settings.failedUrl[obj.state.toLowerCase()] || obj.imageUrl
|
75
|
+
}
|
76
|
+
return obj
|
77
|
+
})
|
78
|
+
return data
|
79
|
+
} else if (statusCode === 400) {
|
80
|
+
throw new Error(`Error Code ${errors.code}: ${errors.message} | requests: ${JSON.stringify(requests)}`)
|
81
|
+
} else {
|
82
|
+
throw new Error(`An unknown error occurred with getThumbnails() | requests: ${JSON.stringify(requests)}`)
|
83
|
+
}
|
84
|
+
})
|
85
|
+
}
|
86
|
+
|
87
|
+
function timeout (ms) {
|
88
|
+
return new Promise(resolve => { setTimeout(resolve, ms) })
|
89
|
+
}
|
90
|
+
|
91
|
+
exports.func = function ({ thumbnailRequests }) {
|
92
|
+
return getThumbnails(thumbnailRequests)
|
93
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('../util/http.js').func
|
3
|
+
const getGeneralToken = require('../util/getGeneralToken.js').func
|
4
|
+
|
5
|
+
// Args
|
6
|
+
exports.required = ['tradeId']
|
7
|
+
exports.optional = ['jar']
|
8
|
+
|
9
|
+
// Docs
|
10
|
+
/**
|
11
|
+
* 🔐 Accept an active trade.
|
12
|
+
* @category Trade
|
13
|
+
* @alias acceptTrade
|
14
|
+
* @param {number} tradeId - The tradeId to accept.
|
15
|
+
* @returns {Promise<void>}
|
16
|
+
* @example const noblox = require("noblox.js")
|
17
|
+
* // Login using your cookie
|
18
|
+
* noblox.acceptTrade(1234)
|
19
|
+
**/
|
20
|
+
|
21
|
+
// Define
|
22
|
+
function acceptTrade (tradeId, jar, xcsrf) {
|
23
|
+
return new Promise((resolve, reject) => {
|
24
|
+
http({
|
25
|
+
url: '//trades.roblox.com/v1/trades/' + tradeId + '/accept',
|
26
|
+
options: {
|
27
|
+
method: 'POST',
|
28
|
+
resolveWithFullResponse: true,
|
29
|
+
jar: jar,
|
30
|
+
headers: {
|
31
|
+
'X-CSRF-TOKEN': xcsrf,
|
32
|
+
'Content-Type': 'application/json'
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}).then((res) => {
|
36
|
+
if (res.statusCode === 200) {
|
37
|
+
resolve()
|
38
|
+
} else {
|
39
|
+
const body = JSON.parse(res.body) || {}
|
40
|
+
|
41
|
+
if (body.errors && body.errors.length > 0) {
|
42
|
+
const errors = body.errors.map((e) => {
|
43
|
+
return e.message
|
44
|
+
})
|
45
|
+
reject(new Error(`${res.statusCode} ${errors.join(', ')}`))
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}).catch(error => reject(error))
|
49
|
+
})
|
50
|
+
}
|
51
|
+
|
52
|
+
exports.func = function (args) {
|
53
|
+
const jar = args.jar
|
54
|
+
return getGeneralToken({ jar: jar })
|
55
|
+
.then(function (xcsrf) {
|
56
|
+
return acceptTrade(args.tradeId, jar, xcsrf)
|
57
|
+
})
|
58
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('../util/http.js').func
|
3
|
+
|
4
|
+
// Args
|
5
|
+
exports.required = ['userId']
|
6
|
+
exports.optional = ['jar']
|
7
|
+
|
8
|
+
// Docs
|
9
|
+
/**
|
10
|
+
* 🔐 Check if the signed in user can trade with another user.
|
11
|
+
* @category Trade
|
12
|
+
* @alias canTradeWith
|
13
|
+
* @param {number} userId - The id of the user.
|
14
|
+
* @returns {Promise<CanTradeResponse>}
|
15
|
+
* @example const noblox = require("noblox.js")
|
16
|
+
* // Login using your cookie
|
17
|
+
* const canTrade = await noblox.canTradeWith(1234)
|
18
|
+
**/
|
19
|
+
|
20
|
+
// Define
|
21
|
+
function canTradeWith (jar, userId) {
|
22
|
+
return new Promise((resolve, reject) => {
|
23
|
+
http({
|
24
|
+
url: '//trades.roblox.com/v1/users/' + userId + '/can-trade-with',
|
25
|
+
options: {
|
26
|
+
method: 'GET',
|
27
|
+
resolveWithFullResponse: true,
|
28
|
+
jar: jar
|
29
|
+
}
|
30
|
+
}).then((res) => {
|
31
|
+
if (res.statusCode === 200) {
|
32
|
+
resolve(JSON.parse(res.body))
|
33
|
+
} else {
|
34
|
+
const body = JSON.parse(res.body) || {}
|
35
|
+
if (body.errors && body.errors.length > 0) {
|
36
|
+
const errors = body.errors.map((e) => {
|
37
|
+
return e.message
|
38
|
+
})
|
39
|
+
reject(new Error(`${res.statusCode} ${errors.join(', ')}`))
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}).catch(error => reject(error))
|
43
|
+
})
|
44
|
+
}
|
45
|
+
|
46
|
+
exports.func = (args) => {
|
47
|
+
return canTradeWith(args.jar, args.userId)
|
48
|
+
}
|
@@ -0,0 +1,84 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('../util/http.js').func
|
3
|
+
const getGeneralToken = require('../util/getGeneralToken.js').func
|
4
|
+
const getCurrentUser = require('../util/getCurrentUser.js').func
|
5
|
+
|
6
|
+
// Args
|
7
|
+
exports.required = ['tradeId', 'targetUserId', 'sendingOffer', 'receivingOffer']
|
8
|
+
exports.optional = ['jar']
|
9
|
+
|
10
|
+
// Docs
|
11
|
+
/**
|
12
|
+
* 🔐 Counter an active incoming trade.
|
13
|
+
* @category Trade
|
14
|
+
* @alias counterTrade
|
15
|
+
* @param {number} tradeId - The id of the active trade
|
16
|
+
* @param {number} targetUserId - The user to send the trade to.
|
17
|
+
* @param {TradeOffer} sendingOffer - The offer to send to the other user.
|
18
|
+
* @param {TradeOffer} recievingOffer - The offer you are requesting from the other user.
|
19
|
+
* @returns {Promise<SendTradeResponse>}
|
20
|
+
* @example const noblox = require("noblox.js")
|
21
|
+
* // Login using your cookie
|
22
|
+
* noblox.counterTrade(1234, 80231025, { userAssetIds: [23289506393] }, { userAssetIds: [32924150919] })
|
23
|
+
**/
|
24
|
+
|
25
|
+
// Define
|
26
|
+
function counterTrade (tradeId, targetUserId, sendingOffer, receivingOffer, jar, xcsrf, loggedInUser) {
|
27
|
+
return new Promise((resolve, reject) => {
|
28
|
+
if (!sendingOffer.userAssetIds || !receivingOffer.userAssetIds) {
|
29
|
+
reject(new Error('Both offers must includes userAssetIds.'))
|
30
|
+
}
|
31
|
+
|
32
|
+
if (!sendingOffer.robux) sendingOffer.robux = 0
|
33
|
+
if (!receivingOffer.robux) receivingOffer.robux = 0
|
34
|
+
|
35
|
+
http({
|
36
|
+
url: '//trades.roblox.com/v1/trades/' + tradeId + '/counter',
|
37
|
+
options: {
|
38
|
+
method: 'POST',
|
39
|
+
resolveWithFullResponse: true,
|
40
|
+
jar: jar,
|
41
|
+
headers: {
|
42
|
+
'X-CSRF-TOKEN': xcsrf,
|
43
|
+
'Content-Type': 'application/json'
|
44
|
+
},
|
45
|
+
body: JSON.stringify({
|
46
|
+
offers: [
|
47
|
+
{
|
48
|
+
userId: targetUserId,
|
49
|
+
...receivingOffer
|
50
|
+
},
|
51
|
+
{
|
52
|
+
userId: loggedInUser,
|
53
|
+
...sendingOffer
|
54
|
+
}
|
55
|
+
]
|
56
|
+
})
|
57
|
+
}
|
58
|
+
}).then((res) => {
|
59
|
+
if (res.statusCode === 200) {
|
60
|
+
resolve(JSON.parse(res.body))
|
61
|
+
} else {
|
62
|
+
const body = JSON.parse(res.body) || {}
|
63
|
+
|
64
|
+
if (body.errors && body.errors.length > 0) {
|
65
|
+
const errors = body.errors.map((e) => {
|
66
|
+
return e.message
|
67
|
+
})
|
68
|
+
reject(new Error(`${res.statusCode} ${errors.join(', ')}`))
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}).catch(error => reject(error))
|
72
|
+
})
|
73
|
+
}
|
74
|
+
|
75
|
+
exports.func = function (args) {
|
76
|
+
const jar = args.jar
|
77
|
+
return Promise.all([
|
78
|
+
getGeneralToken({ jar: jar }),
|
79
|
+
getCurrentUser({ jar: jar, option: 'UserID' })
|
80
|
+
])
|
81
|
+
.then(function (resolvedPromises) {
|
82
|
+
return counterTrade(args.tradeId, args.targetUserId, args.sendingOffer, args.receivingOffer, jar, resolvedPromises[0], resolvedPromises[1])
|
83
|
+
})
|
84
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('../util/http.js').func
|
3
|
+
const getGeneralToken = require('../util/getGeneralToken.js').func
|
4
|
+
|
5
|
+
// Args
|
6
|
+
exports.required = ['tradeId']
|
7
|
+
exports.optional = ['jar']
|
8
|
+
|
9
|
+
// Docs
|
10
|
+
/**
|
11
|
+
* 🔐 Decline an active trade.
|
12
|
+
* @category Trade
|
13
|
+
* @alias declineTrade
|
14
|
+
* @param {number} tradeId - The tradeId to decline.
|
15
|
+
* @returns {Promise<void>}
|
16
|
+
* @example const noblox = require("noblox.js")
|
17
|
+
* // Login using your cookie
|
18
|
+
* noblox.declineTrade(1234)
|
19
|
+
**/
|
20
|
+
|
21
|
+
// Define
|
22
|
+
function declineTrade (tradeId, jar, xcsrf) {
|
23
|
+
return new Promise((resolve, reject) => {
|
24
|
+
http({
|
25
|
+
url: '//trades.roblox.com/v1/trades/' + tradeId + '/decline',
|
26
|
+
options: {
|
27
|
+
method: 'POST',
|
28
|
+
resolveWithFullResponse: true,
|
29
|
+
jar: jar,
|
30
|
+
headers: {
|
31
|
+
'X-CSRF-TOKEN': xcsrf,
|
32
|
+
'Content-Type': 'application/json'
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}).then((res) => {
|
36
|
+
if (res.statusCode === 200) {
|
37
|
+
resolve()
|
38
|
+
} else {
|
39
|
+
const body = JSON.parse(res.body) || {}
|
40
|
+
|
41
|
+
if (body.errors && body.errors.length > 0) {
|
42
|
+
const errors = body.errors.map((e) => {
|
43
|
+
return e.message
|
44
|
+
})
|
45
|
+
reject(new Error(`${res.statusCode} ${errors.join(', ')}`))
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}).catch(error => reject(error))
|
49
|
+
})
|
50
|
+
}
|
51
|
+
|
52
|
+
exports.func = function (args) {
|
53
|
+
const jar = args.jar
|
54
|
+
return getGeneralToken({ jar: jar })
|
55
|
+
.then(function (xcsrf) {
|
56
|
+
return declineTrade(args.tradeId, jar, xcsrf)
|
57
|
+
})
|
58
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('../util/http.js').func
|
3
|
+
|
4
|
+
// Args
|
5
|
+
exports.required = ['tradeId']
|
6
|
+
exports.optional = ['jar']
|
7
|
+
|
8
|
+
// Docs
|
9
|
+
/**
|
10
|
+
* 🔐 Get detailed information for a specific trade.
|
11
|
+
* @category Trade
|
12
|
+
* @alias getTradeInfo
|
13
|
+
* @param {number} tradeId - The id of the trade.
|
14
|
+
* @returns {Promise<TradeInfo>}
|
15
|
+
* @example const noblox = require("noblox.js")
|
16
|
+
* // Login using your cookie
|
17
|
+
* const tradeInfo = await noblox.getTradeInfo(1234)
|
18
|
+
**/
|
19
|
+
|
20
|
+
// Define
|
21
|
+
const getTradeInfo = (jar, tradeId) => {
|
22
|
+
return new Promise((resolve, reject) => {
|
23
|
+
http({
|
24
|
+
url: '//trades.roblox.com/v1/trades/' + tradeId,
|
25
|
+
options: {
|
26
|
+
method: 'GET',
|
27
|
+
resolveWithFullResponse: true,
|
28
|
+
jar: jar
|
29
|
+
}
|
30
|
+
}).then((res) => {
|
31
|
+
if (res.statusCode === 200) {
|
32
|
+
const body = JSON.parse(res.body)
|
33
|
+
body.created = new Date(body.created)
|
34
|
+
if (body.expiration) body.expiration = new Date(body.expiration)
|
35
|
+
|
36
|
+
resolve(body)
|
37
|
+
} else {
|
38
|
+
const body = JSON.parse(res.body) || {}
|
39
|
+
if (body.errors && body.errors.length > 0) {
|
40
|
+
const errors = body.errors.map((e) => {
|
41
|
+
return e.message
|
42
|
+
})
|
43
|
+
reject(new Error(`${res.statusCode} ${errors.join(', ')}`))
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}).catch(error => reject(error))
|
47
|
+
})
|
48
|
+
}
|
49
|
+
|
50
|
+
exports.func = (args) => {
|
51
|
+
return getTradeInfo(args.jar, args.tradeId)
|
52
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
// Includes
|
2
|
+
const getPageResults = require('../util/getPageResults.js').func
|
3
|
+
|
4
|
+
// Args
|
5
|
+
exports.required = ['tradeStatusType']
|
6
|
+
exports.optional = ['sortOrder', 'limit', 'jar']
|
7
|
+
|
8
|
+
// Docs
|
9
|
+
/**
|
10
|
+
* 🔐 Get the trades for a specific category.
|
11
|
+
* @category Trade
|
12
|
+
* @alias getTrades
|
13
|
+
* @param {string} tradeStatusType - The status of the trades to get [Inbound, Outbound, Complete, Inactive].
|
14
|
+
* @param {SortOrder=} [sortOrder=Asc] - The order that the data will be returned in (Asc or Desc)
|
15
|
+
* @param {Limit=} [limit=10] - The number of assets returned in each request (10, 25, 50, or 100)
|
16
|
+
* @returns {Promise<TradeAsset[]>}
|
17
|
+
* @example const noblox = require("noblox.js")
|
18
|
+
* // Login using your cookie
|
19
|
+
* const trades = await noblox.getTrades("Inbound")
|
20
|
+
**/
|
21
|
+
|
22
|
+
// Define
|
23
|
+
exports.func = function (args) {
|
24
|
+
return getPageResults({
|
25
|
+
jar: args.jar,
|
26
|
+
url: `//trades.roblox.com/v1/trades/${args.tradeStatusType}`,
|
27
|
+
sortOrder: args.sortOrder,
|
28
|
+
limit: args.limit
|
29
|
+
}).then(function (results) {
|
30
|
+
results.forEach(result => {
|
31
|
+
result.created = new Date(result.created)
|
32
|
+
if (result.expiration) result.expiration = new Date(result.expiration)
|
33
|
+
})
|
34
|
+
|
35
|
+
return results
|
36
|
+
})
|
37
|
+
}
|