psn-api
Version:
A well-tested library that lets you get trophy, user, and game data from the PlayStation Network.
1,130 lines (1,102 loc) • 62.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var fetch = require('isomorphic-unfetch');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
function _regeneratorRuntime() {
_regeneratorRuntime = function () {
return exports;
};
var exports = {},
Op = Object.prototype,
hasOwn = Op.hasOwnProperty,
defineProperty = Object.defineProperty || function (obj, key, desc) {
obj[key] = desc.value;
},
$Symbol = "function" == typeof Symbol ? Symbol : {},
iteratorSymbol = $Symbol.iterator || "@@iterator",
asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator",
toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
function define(obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}), obj[key];
}
try {
define({}, "");
} catch (err) {
define = function (obj, key, value) {
return obj[key] = value;
};
}
function wrap(innerFn, outerFn, self, tryLocsList) {
var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator,
generator = Object.create(protoGenerator.prototype),
context = new Context(tryLocsList || []);
return defineProperty(generator, "_invoke", {
value: makeInvokeMethod(innerFn, self, context)
}), generator;
}
function tryCatch(fn, obj, arg) {
try {
return {
type: "normal",
arg: fn.call(obj, arg)
};
} catch (err) {
return {
type: "throw",
arg: err
};
}
}
exports.wrap = wrap;
var ContinueSentinel = {};
function Generator() {}
function GeneratorFunction() {}
function GeneratorFunctionPrototype() {}
var IteratorPrototype = {};
define(IteratorPrototype, iteratorSymbol, function () {
return this;
});
var getProto = Object.getPrototypeOf,
NativeIteratorPrototype = getProto && getProto(getProto(values([])));
NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype);
var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
function defineIteratorMethods(prototype) {
["next", "throw", "return"].forEach(function (method) {
define(prototype, method, function (arg) {
return this._invoke(method, arg);
});
});
}
function AsyncIterator(generator, PromiseImpl) {
function invoke(method, arg, resolve, reject) {
var record = tryCatch(generator[method], generator, arg);
if ("throw" !== record.type) {
var result = record.arg,
value = result.value;
return value && "object" == typeof value && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) {
invoke("next", value, resolve, reject);
}, function (err) {
invoke("throw", err, resolve, reject);
}) : PromiseImpl.resolve(value).then(function (unwrapped) {
result.value = unwrapped, resolve(result);
}, function (error) {
return invoke("throw", error, resolve, reject);
});
}
reject(record.arg);
}
var previousPromise;
defineProperty(this, "_invoke", {
value: function (method, arg) {
function callInvokeWithMethodAndArg() {
return new PromiseImpl(function (resolve, reject) {
invoke(method, arg, resolve, reject);
});
}
return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
}
});
}
function makeInvokeMethod(innerFn, self, context) {
var state = "suspendedStart";
return function (method, arg) {
if ("executing" === state) throw new Error("Generator is already running");
if ("completed" === state) {
if ("throw" === method) throw arg;
return doneResult();
}
for (context.method = method, context.arg = arg;;) {
var delegate = context.delegate;
if (delegate) {
var delegateResult = maybeInvokeDelegate(delegate, context);
if (delegateResult) {
if (delegateResult === ContinueSentinel) continue;
return delegateResult;
}
}
if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) {
if ("suspendedStart" === state) throw state = "completed", context.arg;
context.dispatchException(context.arg);
} else "return" === context.method && context.abrupt("return", context.arg);
state = "executing";
var record = tryCatch(innerFn, self, context);
if ("normal" === record.type) {
if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue;
return {
value: record.arg,
done: context.done
};
}
"throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg);
}
};
}
function maybeInvokeDelegate(delegate, context) {
var methodName = context.method,
method = delegate.iterator[methodName];
if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel;
var record = tryCatch(method, delegate.iterator, context.arg);
if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel;
var info = record.arg;
return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel);
}
function pushTryEntry(locs) {
var entry = {
tryLoc: locs[0]
};
1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry);
}
function resetTryEntry(entry) {
var record = entry.completion || {};
record.type = "normal", delete record.arg, entry.completion = record;
}
function Context(tryLocsList) {
this.tryEntries = [{
tryLoc: "root"
}], tryLocsList.forEach(pushTryEntry, this), this.reset(!0);
}
function values(iterable) {
if (iterable) {
var iteratorMethod = iterable[iteratorSymbol];
if (iteratorMethod) return iteratorMethod.call(iterable);
if ("function" == typeof iterable.next) return iterable;
if (!isNaN(iterable.length)) {
var i = -1,
next = function next() {
for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;
return next.value = undefined, next.done = !0, next;
};
return next.next = next;
}
}
return {
next: doneResult
};
}
function doneResult() {
return {
value: undefined,
done: !0
};
}
return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", {
value: GeneratorFunctionPrototype,
configurable: !0
}), defineProperty(GeneratorFunctionPrototype, "constructor", {
value: GeneratorFunction,
configurable: !0
}), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) {
var ctor = "function" == typeof genFun && genFun.constructor;
return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name));
}, exports.mark = function (genFun) {
return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun;
}, exports.awrap = function (arg) {
return {
__await: arg
};
}, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
return this;
}), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
void 0 === PromiseImpl && (PromiseImpl = Promise);
var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) {
return result.done ? result.value : iter.next();
});
}, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () {
return this;
}), define(Gp, "toString", function () {
return "[object Generator]";
}), exports.keys = function (val) {
var object = Object(val),
keys = [];
for (var key in object) keys.push(key);
return keys.reverse(), function next() {
for (; keys.length;) {
var key = keys.pop();
if (key in object) return next.value = key, next.done = !1, next;
}
return next.done = !0, next;
};
}, exports.values = values, Context.prototype = {
constructor: Context,
reset: function (skipTempReset) {
if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined);
},
stop: function () {
this.done = !0;
var rootRecord = this.tryEntries[0].completion;
if ("throw" === rootRecord.type) throw rootRecord.arg;
return this.rval;
},
dispatchException: function (exception) {
if (this.done) throw exception;
var context = this;
function handle(loc, caught) {
return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught;
}
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i],
record = entry.completion;
if ("root" === entry.tryLoc) return handle("end");
if (entry.tryLoc <= this.prev) {
var hasCatch = hasOwn.call(entry, "catchLoc"),
hasFinally = hasOwn.call(entry, "finallyLoc");
if (hasCatch && hasFinally) {
if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
} else if (hasCatch) {
if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
} else {
if (!hasFinally) throw new Error("try statement without catch or finally");
if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
}
}
}
},
abrupt: function (type, arg) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
var finallyEntry = entry;
break;
}
}
finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null);
var record = finallyEntry ? finallyEntry.completion : {};
return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record);
},
complete: function (record, afterLoc) {
if ("throw" === record.type) throw record.arg;
return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel;
},
finish: function (finallyLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel;
}
},
catch: function (tryLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc === tryLoc) {
var record = entry.completion;
if ("throw" === record.type) {
var thrown = record.arg;
resetTryEntry(entry);
}
return thrown;
}
}
throw new Error("illegal catch attempt");
},
delegateYield: function (iterable, resultName, nextLoc) {
return this.delegate = {
iterator: values(iterable),
resultName: resultName,
nextLoc: nextLoc
}, "next" === this.method && (this.arg = undefined), ContinueSentinel;
}
}, exports;
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function () {
var self = this,
args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
var AUTH_BASE_URL = "https://ca.account.sony.com/api/authz/v3/oauth";
/**
* @param accessCode Your access code, typically retrieved by using `exchangeNpssoForAccessCode()`.
* @returns An object containing an access token, refresh token, and expiry times for both.
*/
var exchangeAccessCodeForAuthTokens = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(accessCode) {
var requestUrl, res, raw;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
requestUrl = AUTH_BASE_URL + "/token";
_context.next = 3;
return fetch__default["default"](requestUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: "Basic MDk1MTUxNTktNzIzNy00MzcwLTliNDAtMzgwNmU2N2MwODkxOnVjUGprYTV0bnRCMktxc1A="
},
body: new URLSearchParams({
code: accessCode,
redirect_uri: "com.scee.psxandroid.scecompcall://redirect",
grant_type: "authorization_code",
token_format: "jwt"
}).toString()
});
case 3:
res = _context.sent;
_context.next = 6;
return res.json();
case 6:
raw = _context.sent;
return _context.abrupt("return", {
accessToken: raw.access_token,
expiresIn: raw.expires_in,
idToken: raw.id_token,
refreshToken: raw.refresh_token,
refreshTokenExpiresIn: raw.refresh_token_expires_in,
scope: raw.scope,
tokenType: raw.token_type
});
case 8:
case "end":
return _context.stop();
}
}, _callee);
}));
return function exchangeAccessCodeForAuthTokens(_x) {
return _ref.apply(this, arguments);
};
}();
/**
* @deprecated Use `exchangeAccessCodeForAuthTokens` instead. This alias will be removed in a future version.
*/
var exchangeCodeForAccessToken = exchangeAccessCodeForAuthTokens;
/**
*
* @param npssoToken Your NPSSO token, retrieved from https://ca.account.sony.com/api/v1/ssocookie
* @returns An access code, which can be exchanged for an access token using `exchangeAccessCodeForAuthTokens`.
* @example
* ```ts
* const code = await exchangeNpssoForAccessCode("myNpssoToken");
*
* console.log(code) // --> "v3.XXXXXX"
* ```
*/
var exchangeNpssoForAccessCode = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(npssoToken) {
var _responseHeaders$get;
var queryString, requestUrl, _yield$fetch, responseHeaders, redirectLocation, redirectParams;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
queryString = new URLSearchParams({
access_type: "offline",
client_id: "09515159-7237-4370-9b40-3806e67c0891",
redirect_uri: "com.scee.psxandroid.scecompcall://redirect",
response_type: "code",
scope: "psn:mobile.v2.core psn:clientapp"
}).toString();
requestUrl = AUTH_BASE_URL + "/authorize?" + queryString; // This never returns a 200. As of Oct 10 2021, it seems to return a 302.
_context.next = 4;
return fetch__default["default"](requestUrl, {
headers: {
Cookie: "npsso=" + npssoToken
},
redirect: "manual"
});
case 4:
_yield$fetch = _context.sent;
responseHeaders = _yield$fetch.headers;
if (!(!responseHeaders.has("location") || !((_responseHeaders$get = responseHeaders.get("location")) != null && _responseHeaders$get.includes("?code=")))) {
_context.next = 8;
break;
}
throw new Error("\n There was a problem retrieving your PSN access code. Is your NPSSO code valid?\n To get a new NPSSO code, visit https://ca.account.sony.com/api/v1/ssocookie.\n ");
case 8:
redirectLocation = responseHeaders.get("location");
redirectParams = new URLSearchParams(redirectLocation.split("redirect/")[1]);
return _context.abrupt("return", redirectParams.get("code"));
case 11:
case "end":
return _context.stop();
}
}, _callee);
}));
return function exchangeNpssoForAccessCode(_x) {
return _ref.apply(this, arguments);
};
}();
/**
* @deprecated Use `exchangeNpssoForAccessCode` instead. This alias will be removed in a future version.
*/
var exchangeNpssoForCode = exchangeNpssoForAccessCode;
var exchangeRefreshTokenForAuthTokens = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(refreshToken) {
var requestUrl, res, raw;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
requestUrl = AUTH_BASE_URL + "/token";
_context.next = 3;
return fetch__default["default"](requestUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: "Basic MDk1MTUxNTktNzIzNy00MzcwLTliNDAtMzgwNmU2N2MwODkxOnVjUGprYTV0bnRCMktxc1A="
},
body: new URLSearchParams({
refresh_token: refreshToken,
grant_type: "refresh_token",
token_format: "jwt",
scope: "psn:mobile.v2.core psn:clientapp"
}).toString()
});
case 3:
res = _context.sent;
_context.next = 6;
return res.json();
case 6:
raw = _context.sent;
return _context.abrupt("return", {
accessToken: raw.access_token,
expiresIn: raw.expires_in,
idToken: raw.id_token,
refreshToken: raw.refresh_token,
refreshTokenExpiresIn: raw.refresh_token_expires_in,
scope: raw.scope,
tokenType: raw.token_type
});
case 8:
case "end":
return _context.stop();
}
}, _callee);
}));
return function exchangeRefreshTokenForAuthTokens(_x) {
return _ref.apply(this, arguments);
};
}();
var call = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config, authorization, bodyPayload) {
var _config$method;
var response;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return fetch__default["default"](config.url, {
method: (_config$method = config == null ? void 0 : config.method) != null ? _config$method : "GET",
headers: _extends({
Authorization: "Bearer " + authorization.accessToken,
"Content-Type": "application/json"
}, config == null ? void 0 : config.headers),
body: JSON.stringify(bodyPayload)
});
case 2:
response = _context.sent;
_context.next = 5;
return response.json();
case 5:
return _context.abrupt("return", _context.sent);
case 6:
case "end":
return _context.stop();
}
}, _callee);
}));
return function call(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
var GRAPHQL_BASE_URL = "https://web.np.playstation.com/api/graphql/v1/op";
/**
* GraphQL endpoints work differently to others in the codebase.
*
* The hashes in this file are reverse engineered from app-<hash>.js file loaded by the page
* at https://library.playstation.com/recently-played. Following the code in that file leads
* to some Apollo GraphQL code related to persisted queries. This means the request needs to
* contain a SHA256 hash of the GraphQL query being executed. Searching for PersistedQueryLink
* and createPersistedQueryLink_hashes, and an AST function in Sony's JS source and debugging
* will surface the exact GraphQL query that's passed to the hash function on the page.
*
* Thankfully it's easier to figure out future endpoints and hashes by:
*
* 1. Visiting a page, e.g https://library.playstation.com/recently-played
* 2. Using DevTools to find requests to https://web.np.playstation.com/api/graphql/v1/op
* 3. Decoding the URL parameters to find the correct SHA256 hash and some of the supported parameters
*/
// Hash is computed from the following query (without surrounding quotes):
// "query getUserGameList($categories: String, $limit: Int, $orderBy: String, $subscriptionService: SubscriptionService) {\n gameLibraryTitlesRetrieve(categories: $categories, limit: $limit, orderBy: $orderBy, subscriptionService: $subscriptionService) {\n __typename\n games {\n __typename\n conceptId\n entitlementId\n image {\n __typename\n url\n }\n isActive\n lastPlayedDateTime\n name\n platform\n productId\n subscriptionService\n titleId\n }\n }\n}\n"
var getUserGameListHash = "e780a6d8b921ef0c59ec01ea5c5255671272ca0d819edb61320914cf7a78b3ae";
/**
* A call to this function will retrieve recently played games for the user associated
* with the npsso token provided to this module during initialisation.
*
* This is useful if you want recent activity that isn't tied to trophy progress.
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
*/
var getRecentlyPlayedGames = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, options) {
var _options, _options$limit, limit, _options$categories, categories, url, response;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
if (options === void 0) {
options = {};
}
_options = options, _options$limit = _options.limit, limit = _options$limit === void 0 ? 50 : _options$limit, _options$categories = _options.categories, categories = _options$categories === void 0 ? ["ps4_game", "ps5_native_game"] : _options$categories;
url = new URL(GRAPHQL_BASE_URL);
url.searchParams.set("operationName", "getUserGameList");
url.searchParams.set("variables", JSON.stringify({
limit: limit,
categories: categories.join(",")
}));
url.searchParams.set("extensions", JSON.stringify({
persistedQuery: {
version: 1,
sha256Hash: getUserGameListHash
}
}));
_context.next = 8;
return call({
url: url.toString()
}, authorization);
case 8:
response = _context.sent;
if (!(!response.data || !response.data.gameLibraryTitlesRetrieve)) {
_context.next = 11;
break;
}
throw new Error(JSON.stringify(response));
case 11:
return _context.abrupt("return", response);
case 12:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getRecentlyPlayedGames(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
exports.TrophyRarity = void 0;
(function (TrophyRarity) {
TrophyRarity[TrophyRarity["UltraRare"] = 0] = "UltraRare";
TrophyRarity[TrophyRarity["VeryRare"] = 1] = "VeryRare";
TrophyRarity[TrophyRarity["Rare"] = 2] = "Rare";
TrophyRarity[TrophyRarity["Common"] = 3] = "Common";
})(exports.TrophyRarity || (exports.TrophyRarity = {}));
var _excluded = ["headerOverrides"];
var buildRequestUrl = function buildRequestUrl(baseUrl, endpointUrl, options, args) {
if (options === void 0) {
options = {};
}
if (args === void 0) {
args = {};
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- This is an intentional pick.
var _options = options,
pickedOptions = _objectWithoutPropertiesLoose(_options, _excluded);
var concatenated = baseUrl + "/" + endpointUrl;
var withoutDoubleSlashes = concatenated.replace(/([^:]\/)\/+/g, "$1");
var withArgs = withoutDoubleSlashes;
var queryParamValues = {};
for (var _i = 0, _Object$entries = Object.entries(_extends({}, args, pickedOptions)); _i < _Object$entries.length; _i++) {
var _Object$entries$_i = _Object$entries[_i],
argKey = _Object$entries$_i[0],
argValue = _Object$entries$_i[1];
if (withArgs.includes(":" + argKey)) {
withArgs = withArgs.replace(":" + argKey, String(argValue));
} else if (argValue !== undefined) {
queryParamValues[argKey] = String(argValue);
}
}
var queryString = new URLSearchParams(queryParamValues).toString();
return queryString.length > 0 ? withArgs + "?" + queryString : withArgs;
};
var SEARCH_BASE_URL = "https://m.np.playstation.com/api/search";
var makeUniversalSearch = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, searchTerm, domain) {
var url;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(SEARCH_BASE_URL, "/v1/universalSearch");
_context.next = 3;
return call({
url: url,
method: "POST"
}, authorization, {
searchTerm: searchTerm,
domainRequests: [{
domain: domain
}]
});
case 3:
return _context.abrupt("return", _context.sent);
case 4:
case "end":
return _context.stop();
}
}, _callee);
}));
return function makeUniversalSearch(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
var TROPHY_BASE_URL = "https://m.np.playstation.com/api/trophy";
/**
* A call to this function will retrieve the trophy list of a
* single - or all - trophy groups for a title. A title can have multiple
* groups of trophies (a `"default"` group which all titles have, and additional
* groups starting with the name `"001"` and incrementing for each additional group). To retrieve
* trophies from all groups within a title (ie. the full trophy set), then
* `trophyGroupId` should be set to `"all"`.
*
* When the title platform is PS3, PS4 or PS Vita you __must__ specify the
* `npServiceName` parameter as `"trophy"`.
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
* @param npCommunicationId Unique ID of the title.
* @param trophyGroupId `"all"` to return all trophies for the title, otherwise restrict results to a specific trophy group (such as a DLC).
* @param options.npServiceName `"trophy"` for PS3, PS4, or PS Vita platforms. `"trophy2"` for the PS5 platform.
* @param options.limit Limit the number of trophies returned.
* @param options.offset Return trophy data from this result onwards.
* @param options.headerOverrides Override the headers in the request to the PSN API, such as to change the language.
*/
var getTitleTrophies = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, npCommunicationId, trophyGroupId, options) {
var url;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(TROPHY_BASE_URL, "/v1/npCommunicationIds/:npCommunicationId/trophyGroups/:trophyGroupId/trophies", options, {
npCommunicationId: npCommunicationId,
trophyGroupId: trophyGroupId
});
_context.next = 3;
return call({
url: url,
headers: options == null ? void 0 : options.headerOverrides
}, authorization);
case 3:
return _context.abrupt("return", _context.sent);
case 4:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getTitleTrophies(_x, _x2, _x3, _x4) {
return _ref.apply(this, arguments);
};
}();
/**
* A title may have multiple groups of trophies. This is most commonly
* seen in games which have DLC expansions where additional trophies are added.
*
* You can call this function for a specific title - using the
* unique `npCommunicationId` for the title - and you will receive a
* summary of all of the trophy groups associated with the title.
* This also includes a summary of the number of trophies for the
* title, broken down by group and grade (gold, silver, etc.).
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
* @param npCommunicationId The unique ID of the game title you wish to retrieve the trophy groups list for.
* @param options.npServiceName `"trophy"` for PS3, PS4, or PS Vita platforms. `"trophy2"` for the PS5 platform.
* @param options.headerOverrides Override the headers in the request to the PSN API, such as to change the language.
*/
var getTitleTrophyGroups = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, npCommunicationId, options) {
var url;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(TROPHY_BASE_URL, "/v1/npCommunicationIds/:npCommunicationId/trophyGroups", options, {
npCommunicationId: npCommunicationId
});
_context.next = 3;
return call({
url: url,
headers: options == null ? void 0 : options.headerOverrides
}, authorization);
case 3:
return _context.abrupt("return", _context.sent);
case 4:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getTitleTrophyGroups(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
/**
* A call to this function will retrieve a summarized list of titles played
* by a user, ordered by recent trophy unlocks. The maximum amount that can
* be returned by a single call is 800 (assuming a `limit` option of 800 is set).
* If the user has more titles than the given `limit` option, subsequent calls
* of this funciton must be made to fetch the complete list by paging via the
* `offset` option.
*
* The numeric `accountId` can be that of any PSN account for which the authenticating
* account has permissions to view the trophy list. When querying the titles
* associated with the authenticating account, the numeric `accountId` can be
* substituted with `"me"`.
*
* To fetch more detailed account progress for a title, the `getUserTrophiesEarnedForTitle()`
* function can be used.
*
* To find a user's `accountId`, the `makeUniversalSearch()` function can be used.
*
* Included in the information returned is the titles' unique `npCommunicationId`.
* This is required to make use of subsequent functions for requesting more specific
* detail about a title's trophies.
*
* The results are presented in order of the `lastUpdatedDateTime` for the title,
* so the first result will be the title for which a trophy was most recently earned
* (or synced for the first time in the case of a game with 0% progress).
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
* @param accountId The account whose trophy list is being accessed. Use `"me"` for the authenticating account.
* @param options.limit Limit the number of titles returned.
* @param options.offset Return title data from this result onwards.
* @param options.headerOverrides Override the headers in the request to the PSN API, such as to change the language.
*/
var getUserTitles = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, accountId, options) {
var url;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(TROPHY_BASE_URL, "/v1/users/:accountId/trophyTitles", options, {
accountId: accountId
});
_context.next = 3;
return call({
url: url,
headers: options == null ? void 0 : options.headerOverrides
}, authorization);
case 3:
return _context.abrupt("return", _context.sent);
case 4:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getUserTitles(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
/**
* A call to this function will retrieve the earned status of trophies for a user
* from either a single - or all - trophy groups in a title. A title can have
* multiple groups of trophies (a `"default"` group which all titles have, and
* additional groups starting with a name of `"001"` and incrementing for each
* additional group). To retrieve trophies from all groups within a title
* (ie. the full trophy set), then `trophyGroupId` should be set to `"all"`.
*
* The numeric `accountId` can be that of any PSN account for which the
* authenticating account has permissions to view the trophy list.
* When querying the titles associated with the authenticating account, the
* numeric `accountId` can be substituted with `"me"`.
*
* To find a user's `accountId`, the `makeUniversalSearch()` function can be used.
*
* This function returns the earned status of the
* trophy only and no additional descriptive metadata (ie. trophy name,
* trophy description). Use `getTitleTrophies()` to obtain this information.
*
* When the title platform is PS3, PS4, or PS Vita, you __must__ specify the
* `npServiceName` option as `"trophy"`.
*
* If you attempt to query a title which the user does not have associated
* with their account (ie. the title has not been launched and allowed to
* sync at least once) then a Resource Not Found error will be thrown.
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
* @param accountId The account whose trophy list is being accessed. Use `"me"` for the authenticating account.
* @param npCommunicationId Unique ID of the title.
* @param trophyGroupId `"all"` to return all trophies for the title, otherwise restrict results to a specific trophy group (such as a DLC).
* @param options.npServiceName `"trophy"` for PS3, PS4, or PS Vita platforms. `"trophy2"` for the PS5 platform.
* @param options.limit Limit the number of trophies returned.
* @param options.offset Return trophy data from this result onwards.
* @param options.headerOverrides Override the headers in the request to the PSN API, such as to change the language.
*/
var getUserTrophiesEarnedForTitle = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, accountId, npCommunicationId, trophyGroupId, options) {
var url, response, _response$error$messa, _response$error;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(TROPHY_BASE_URL, "/v1/users/:accountId/npCommunicationIds/:npCommunicationId/trophyGroups/:trophyGroupId/trophies", options, {
accountId: accountId,
npCommunicationId: npCommunicationId,
trophyGroupId: trophyGroupId
});
_context.next = 3;
return call({
url: url,
headers: options == null ? void 0 : options.headerOverrides
}, authorization);
case 3:
response = _context.sent;
if (!(response != null && response.error)) {
_context.next = 6;
break;
}
throw new Error((_response$error$messa = response == null ? void 0 : (_response$error = response.error) == null ? void 0 : _response$error.message) != null ? _response$error$messa : "Unexpected Error");
case 6:
return _context.abrupt("return", response);
case 7:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getUserTrophiesEarnedForTitle(_x, _x2, _x3, _x4, _x5) {
return _ref.apply(this, arguments);
};
}();
/**
* A request to this endpoint function will retrieve a summary of the trophies earned for
* a user broken down by trophy group within a title. A title can have
* multiple groups of trophies (a `"default"` group which all titles have,
* and additional groups beginning with the name `"001"` and incrementing for
* each additional group).
*
* The numeric `accountId` can be that of any PSN account for which the
* authenticating account has permissions to view the trophy list.
* When querying the titles associated with the authenticating account, the
* numeric `accountId` can be substituted with `"me"`.
*
* To find a user's `accountId`, the `makeUniversalSearch()` function can be used.
*
* This function calls an endpoint that returns the earned status of the
* trophy only and no additional descriptive metadata (ie. trophy name,
* trophy description). Use `getTitleTrophies()` to obtain this information.
*
* When the title platform is PS3, PS4 or PS Vita you __must__ specify the
* `npServiceName` option as `"trophy"`.
*
* If you attempt to query a title which the user does not have associated
* with their account (ie. the title has not been launched and allowed to
* sync at least once) then a Resource Not Found error will be thrown.
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
* @param accountId The account whose trophy list is being accessed. Use `"me"` for the authenticating account.
* @param npCommunicationId Unique ID of the title.
* @param options.npServiceName `"trophy"` for PS3, PS4, or PS Vita platforms. `"trophy2"` for the PS5 platform.
* @param options.headerOverrides Override the headers in the request to the PSN API, such as to change the language.
*/
var getUserTrophyGroupEarningsForTitle = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, accountId, npCommunicationId, options) {
var url, response, _response$error$messa, _response$error;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(TROPHY_BASE_URL, "/v1/users/:accountId/npCommunicationIds/:npCommunicationId/trophyGroups", options, {
accountId: accountId,
npCommunicationId: npCommunicationId
});
_context.next = 3;
return call({
url: url,
headers: options == null ? void 0 : options.headerOverrides
}, authorization);
case 3:
response = _context.sent;
if (!(response != null && response.error)) {
_context.next = 6;
break;
}
throw new Error((_response$error$messa = response == null ? void 0 : (_response$error = response.error) == null ? void 0 : _response$error.message) != null ? _response$error$messa : "Unexpected Error");
case 6:
return _context.abrupt("return", response);
case 7:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getUserTrophyGroupEarningsForTitle(_x, _x2, _x3, _x4) {
return _ref.apply(this, arguments);
};
}();
/**
* A call to this function will retrieve an overall summary of the number of
* trophies earned for a user broken down by grade, as well as their current
* overall trophy level, progress towards the next level, and which tier their
* current level falls in to. The tiers are based on the [level changes introduced in 2020](https://andshrew.github.io/PlayStation-Trophies/images/psn-trophy-tiers.png).
*
* The numeric `accountId` can be that of any PSN account for which the
* authenticating account has permissions to view the trophy list.
* When querying the titles associated with the authenticating account, the
* numeric `accountId` can be substituted with `"me"`.
*
* To find a user's `accountId`, the `makeUniversalSearch()` function can be used.
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
* @param accountId The account whose trophy list is being accessed. Use `"me"` for the authenticating account.
* @param options.headerOverrides Override the headers in the request to the PSN API, such as to change the language.
*/
var getUserTrophyProfileSummary = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, accountId, options) {
var url;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(TROPHY_BASE_URL, "/v1/users/:accountId/trophySummary", options, {
accountId: accountId
});
_context.next = 3;
return call({
url: url,
headers: options == null ? void 0 : options.headerOverrides
}, authorization);
case 3:
return _context.abrupt("return", _context.sent);
case 4:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getUserTrophyProfileSummary(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
var USER_BASE_URL = "https://m.np.playstation.com/api/userProfile/v1/internal/users";
var USER_GAMES_BASE_URL = "https://m.np.playstation.com/api/gamelist/v2/users";
var USER_LEGACY_BASE_URL = "https://us-prof.np.community.playstation.net/userProfile/v1/users";
/**
* A call to this function will retrieve the basic presence information of the accountId being requested.
* If the account's profile cannot be found (either due to non-existence or privacy settings),
* an error will be thrown.
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
* @param accountId The accountId for the user you wish to retrieve a profile for.
* @param options Optional - Additional headerOverride options to provide for the request
*/
var getBasicPresence = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, accountId, options) {
var url, response, _response$error$messa, _response$error;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(USER_BASE_URL, "/:accountId/basicPresences?type=primary", options, {
accountId: accountId
});
_context.next = 3;
return call({
url: url
}, authorization);
case 3:
response = _context.sent;
if (!(response != null && response.error)) {
_context.next = 6;
break;
}
throw new Error((_response$error$messa = response == null ? void 0 : (_response$error = response.error) == null ? void 0 : _response$error.message) != null ? _response$error$messa : "Unexpected Error");
case 6:
return _context.abrupt("return", response);
case 7:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getBasicPresence(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
/**
* A call to this function will retrieve some profile information of the accountId being requested.
* If the account's profile cannot be found (either due to non-existence or privacy settings),
* an error will be thrown.
*
* @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`.
* @param accountId The accountId for the user you wish to retrieve a profile for.
*/
var getProfileFromAccountId = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, accountId, options) {
var url, response, _response$error$messa, _response$error;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
url = buildRequestUrl(USER_BASE_URL, "/:accountId/profiles", options, {
accountId: accountId
});
_context.next = 3;
return call({
url: url
}, authorization);
case 3:
response = _context.sent;
if (!(response != null && response.error)) {
_context.next = 6;
break;
}
throw new Error((_response$error$messa = response == null ? void 0 : (_response$error = response.error) == null ? void 0 : _response$error.message) != null ? _response$error$messa : "Unexpected Error");
case 6:
return _context.abrupt("return", response);
case 7:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getProfileFromAccountId(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
/**
* A call to