├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── lib └── index.js ├── package.json └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | node_modules/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 0.10 5 | - 0.12 6 | - iojs -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 The Chunk Network 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mojang-api 2 | 3 | [![Build Status](https://travis-ci.org/thechunknetwork/mojang-api.svg)](https://travis-ci.org/thechunknetwork/mojang-api) 4 | 5 | `mojang-api` is a simple wrapper around the [Mojang API](http://wiki.vg/Mojang_API). It is simple and low-dependency (only needing the 6 | excellent [request](https://www.npmjs.com/package/request) library). 7 | 8 | ## Installation 9 | 10 | npm install --save mojang-api 11 | 12 | ## Usage 13 | 14 | ### MojangAPI.uuidAt(username, time, cb) 15 | 16 | Parameters: 17 | 18 | * **username**: The username to resolve the UUID for 19 | * **time**: Either a Date or a Number 20 | * **cb**: Callback that accepts the form of function(err, apiResponse) 21 | 22 | Example: 23 | ```js 24 | var MojangAPI = require('mojang-api'); 25 | var date = new Date(); 26 | date.setMonth(0); // 0 = January 27 | MojangAPI.uuidAt('jeb_', date, function(err, res) { 28 | if (err) 29 | console.log(err); 30 | else 31 | console.log("On " + date + ", jeb_'s UUID was " + res.id); 32 | }); 33 | ``` 34 | 35 | ### MojangAPI.nameHistory(uuid, cb) 36 | 37 | Parameters: 38 | 39 | * **uuid**: The UUID to look up 40 | * **cb**: Callback that accepts the form of function(err, apiResponse) 41 | 42 | Example: 43 | ```js 44 | var MojangAPI = require('mojang-api'); 45 | MojangAPI.nameHistory('853c80ef3c3749fdaa49938b674adae6', function(err, res) { 46 | if (err) 47 | console.log(err); 48 | else { 49 | if (res.length == 1) { 50 | console.log(res[0].name + " is very content with their existing username, because they didn't change it. Excellent job.") 51 | } else { 52 | var lastChange = res[res.length - 1]; 53 | var at = new Date(lastChange.changedToAt); 54 | console.log(lastChange.name + " wasn't so content with their username. They last changed their username at " + at + "."); 55 | } 56 | } 57 | }); 58 | ``` 59 | 60 | ### MojangAPI.nameToUuid(names, cb) 61 | 62 | Parameters: 63 | 64 | * **names**: The names to look up as an array or a single username as a string 65 | * **cb**: Callback that accepts the form of function(err, apiResponse) 66 | 67 | Example: 68 | ```js 69 | var MojangAPI = require('mojang-api'); 70 | MojangAPI.nameToUuid('jeb_', function(err, res) { 71 | if (err) 72 | console.log(err); 73 | else { 74 | console.log(res[0].name + "? No, they're " + res[0].id + " to me."); 75 | } 76 | }); 77 | ``` 78 | 79 | ### MojangAPI.profile(uuid, cb) 80 | 81 | Parameters: 82 | 83 | * **uuid**: The UUID to lookup 84 | * **cb**: Callback that accepts the form of function(err, apiResponse) 85 | 86 | Example: 87 | ```js 88 | var MojangAPI = require('mojang-api'); 89 | MojangAPI.profile('853c80ef3c3749fdaa49938b674adae6', function(err, res) { 90 | if (err) 91 | console.log(err); 92 | else { 93 | console.log(res.id + " is also known as " + res.name + "."); 94 | } 95 | }); 96 | ``` 97 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/index'); -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | 3 | var MojangAPI = function(){ 4 | if (!(this instanceof MojangAPI)) return new MojangAPI(); 5 | }; 6 | 7 | MojangAPI.prototype._simpleGet = function(url, cb) { 8 | request(url, { json: true }, function(err, res, body) { 9 | if (typeof body === 'undefined') 10 | return cb(new Error('body is undefined')); 11 | 12 | if (body.error) 13 | return cb(new Error(body.error + ": " + body.errorMessage)); 14 | 15 | cb(null, body); 16 | }); 17 | }; 18 | 19 | MojangAPI.prototype.uuidAt = function(username, time, cb) { 20 | if (typeof username !== "string") 21 | throw new Error('username is not a string'); 22 | 23 | var unixTimestamp; 24 | 25 | if (time instanceof Date) { 26 | unixTimestamp = Math.ceil(time.getTime() / 1000); 27 | } else if (typeof time === 'number') { 28 | unixTimestamp = Math.ceil(time); 29 | } else { 30 | throw new Error('timestamp was not a Number or Date'); 31 | } 32 | 33 | if (typeof cb !== "function") 34 | throw new Error('callback was not a function'); 35 | 36 | this._simpleGet('https://api.mojang.com/users/profiles/minecraft/' + encodeURIComponent(username) + '?at=' + unixTimestamp, cb); 37 | }; 38 | 39 | MojangAPI.prototype.nameHistory = function(uuid, cb) { 40 | if (typeof uuid !== "string") 41 | throw new Error('uuid is not a string'); 42 | 43 | if (typeof cb !== "function") 44 | throw new Error('callback was not a function'); 45 | 46 | this._simpleGet('https://api.mojang.com/user/profiles/' + encodeURIComponent(uuid) + '/names', cb); 47 | }; 48 | 49 | MojangAPI.prototype.nameToUuid = function(names, cb) { 50 | var nameArray; 51 | 52 | if (names instanceof Array) 53 | nameArray = names; 54 | else if (typeof names === "string") 55 | nameArray = [names]; 56 | else 57 | throw new Error('names is not a string or Array'); 58 | 59 | if (typeof cb !== "function") 60 | throw new Error('callback was not a function'); 61 | 62 | request.post('https://api.mojang.com/profiles/minecraft', { json: true, body: nameArray }, function(err, res, body) { 63 | if (body.error) 64 | return cb.error(new Error(body.error + ": " + body.errorMessage)); 65 | 66 | cb(null, body); 67 | }); 68 | }; 69 | 70 | MojangAPI.prototype.profile = function(uuid, cb) { 71 | if (typeof uuid !== "string") 72 | throw new Error('uuid is not a string'); 73 | 74 | if (typeof cb !== "function") 75 | throw new Error('callback was not a function'); 76 | 77 | this._simpleGet('https://sessionserver.mojang.com/session/minecraft/profile/' + encodeURIComponent(uuid), cb); 78 | }; 79 | 80 | module.exports = MojangAPI(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mojang-api", 3 | "version": "0.0.2", 4 | "description": "A simple wrapper around Mojang's API", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "lab --verbose --colors" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/thechunknetwork/mojang-api.git" 12 | }, 13 | "keywords": [ 14 | "minecraft", 15 | "mojang" 16 | ], 17 | "author": "Tux ", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/thechunknetwork/mojang-api/issues" 21 | }, 22 | "homepage": "https://github.com/thechunknetwork/mojang-api", 23 | "dependencies": { 24 | "request": "^2.53.0" 25 | }, 26 | "devDependencies": { 27 | "chai": "^2.3.0", 28 | "lab": "^5.9.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var expect = require('chai').expect; 3 | var lab = Lab.script(); 4 | var MojangAPI = require('../lib'); 5 | 6 | // This username and UUID is unlikely to change, given this is one of the "official" Mojang skin accounts. 7 | // See http://minecraft.gamepedia.com/Mob_head#Mojang_skins 8 | var USERNAME = 'MHF_Chicken'; 9 | var UUID = '92deafa9430742d9b00388601598d6c0'; 10 | 11 | // For namesToUuid test, second username: 12 | var USERNAME2 = 'MHF_Cake'; 13 | 14 | lab.experiment('MojangAPI', function() { 15 | lab.experiment('uuidAt', function() { 16 | lab.experiment('throws an Error if', function() { 17 | lab.test('username was not specified', function(done) { 18 | expect(MojangAPI.uuidAt).to.throw(Error); 19 | done(); 20 | }); 21 | 22 | lab.test('username was not valid', function(done) { 23 | expect(function() { 24 | MojangAPI.uuidAt(42) 25 | }).to.throw(Error); 26 | done(); 27 | }); 28 | 29 | lab.test('date was not specified', function(done) { 30 | expect(function() { 31 | MojangAPI.uuidAt(USERNAME) 32 | }).to.throw(Error); 33 | done(); 34 | }); 35 | 36 | lab.test('date was not valid', function(done) { 37 | expect(function() { 38 | MojangAPI.uuidAt(USERNAME, 'derp') 39 | }).to.throw(Error); 40 | done(); 41 | }); 42 | 43 | lab.test('callback was not specified', function(done) { 44 | expect(function() { 45 | MojangAPI.uuidAt(USERNAME, new Date()) 46 | }).to.throw(Error); 47 | done(); 48 | }); 49 | 50 | lab.test('callback was not a function', function(done) { 51 | expect(function() { 52 | MojangAPI.uuidAt(USERNAME, new Date(), 42) 53 | }).to.throw(Error); 54 | done(); 55 | }); 56 | }); 57 | 58 | lab.experiment('works when timestamp is a', function() { 59 | lab.test('number', function(done) { 60 | MojangAPI.uuidAt(USERNAME, 1432789369, function(err, resp) { 61 | expect(err).to.be.null; 62 | expect(resp).to.have.property('id').and.equal(UUID); 63 | expect(resp).to.have.property('name', USERNAME); 64 | done(); 65 | }); 66 | }); 67 | 68 | lab.test('Date', function(done) { 69 | MojangAPI.uuidAt(USERNAME, new Date(1432789369000), function(err, resp) { 70 | expect(err).to.be.null; 71 | expect(resp).to.have.property('id', UUID); 72 | expect(resp).to.have.property('name', USERNAME); 73 | done(); 74 | }); 75 | }); 76 | }); 77 | }); 78 | 79 | lab.experiment('nameHistory', function() { 80 | lab.experiment('throws an Error if', function() { 81 | lab.test('username was not specified', function(done) { 82 | expect(MojangAPI.nameHistory).to.throw(Error); 83 | done(); 84 | }); 85 | 86 | lab.test('username was not valid', function(done) { 87 | expect(function() { 88 | MojangAPI.nameHistory(42) 89 | }).to.throw(Error); 90 | done(); 91 | }); 92 | 93 | lab.test('callback was not specified', function(done) { 94 | expect(function() { 95 | MojangAPI.nameHistory(UUID) 96 | }).to.throw(Error); 97 | done(); 98 | }); 99 | 100 | lab.test('callback was not a function', function(done) { 101 | expect(function() { 102 | MojangAPI.nameHistory(UUID, 'hi') 103 | }).to.throw(Error); 104 | done(); 105 | }); 106 | }); 107 | 108 | lab.test('produces correct results', function(done) { 109 | MojangAPI.nameHistory(UUID, function(err, resp) { 110 | expect(err).to.be.null; 111 | expect(resp).to.be.instanceof(Array); 112 | done(); 113 | }); 114 | }); 115 | }); 116 | 117 | lab.experiment('nameToUuid', function() { 118 | lab.experiment('throws an error if', function() { 119 | lab.test('names are not specified', function(done) { 120 | expect(MojangAPI.nameToUuid).to.throw(Error); 121 | done(); 122 | }); 123 | 124 | lab.test('names was not valid', function(done) { 125 | expect(function() { 126 | MojangAPI.nameToUuid(42) 127 | }).to.throw(Error); 128 | done(); 129 | }); 130 | 131 | lab.test('callback was not specified', function(done) { 132 | expect(function() { 133 | MojangAPI.nameToUuid(USERNAME); 134 | }).to.throw(Error); 135 | done(); 136 | }); 137 | 138 | lab.test('callback was not a function', function(done) { 139 | expect(function() { 140 | MojangAPI.nameToUuid(USERNAME, 'hi') 141 | }).to.throw(Error); 142 | done(); 143 | }); 144 | }); 145 | 146 | lab.experiment('works when names is a', function() { 147 | lab.test('string', function(done) { 148 | MojangAPI.nameToUuid(USERNAME, function(err, resp) { 149 | expect(err).to.be.null; 150 | expect(resp).to.be.instanceof(Array); 151 | done(); 152 | }); 153 | }); 154 | 155 | lab.test('single-element Array', function(done) { 156 | MojangAPI.nameToUuid([USERNAME], function(err, resp) { 157 | expect(err).to.be.null; 158 | expect(resp).to.be.instanceof(Array); 159 | done(); 160 | }); 161 | }); 162 | 163 | lab.test('multi-element Array', function(done) { 164 | MojangAPI.nameToUuid([USERNAME, USERNAME2], function(err, resp) { 165 | expect(err).to.be.null; 166 | expect(resp).to.be.instanceof(Array).and.have.length(2); 167 | done(); 168 | }); 169 | }); 170 | }); 171 | }); 172 | 173 | lab.experiment('profile', function() { 174 | lab.experiment('throws an Error if', function() { 175 | lab.test('uuid was not specified', function(done) { 176 | expect(MojangAPI.profile).to.throw(Error); 177 | done(); 178 | }); 179 | 180 | lab.test('uuid was not valid', function(done) { 181 | expect(function() { 182 | MojangAPI.profile(42) 183 | }).to.throw(Error); 184 | done(); 185 | }); 186 | 187 | lab.test('callback was not specified', function(done) { 188 | expect(function() { 189 | MojangAPI.profile(UUID) 190 | }).to.throw(Error); 191 | done(); 192 | }); 193 | 194 | lab.test('callback was not a function', function(done) { 195 | expect(function() { 196 | MojangAPI.profile(UUID, 'hi') 197 | }).to.throw(Error); 198 | done(); 199 | }); 200 | }); 201 | 202 | lab.test('produces correct results', function(done) { 203 | MojangAPI.profile(UUID, function(err, resp) { 204 | expect(err).to.be.null; 205 | expect(resp).to.have.property('id', UUID); 206 | expect(resp).to.have.property('name', USERNAME); 207 | expect(resp).to.have.property('properties').and.to.be.instanceof(Array); 208 | done(); 209 | }); 210 | }); 211 | }); 212 | }); 213 | 214 | exports.lab = lab; --------------------------------------------------------------------------------