UNPKG

psn-api

Version:

A well-tested library that lets you get trophy, user, and game data from the PlayStation Network.

1,107 lines (1,084 loc) 68.8 kB
import fetch from 'isomorphic-unfetch'; 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(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(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(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(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); }; }(); var TrophyRarity; (function (TrophyRarity) { TrophyRarity[TrophyRarity["UltraRare"] = 0] = "UltraRare"; TrophyRarity[TrophyRarity["VeryRare"] = 1] = "VeryRare"; TrophyRarity[TrophyRarity["Rare"] = 2] = "Rare"; TrophyRarity[TrophyRarity["Common"] = 3] = "Common"; })(TrophyRarity || (TrophyRarity = {})); var _excluded$1 = ["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$1); 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); }; }(); var _excluded = ["headerOverrides"]; /** * A call to this function will retrieve a summary of the trophies earned by * a user for specific titles. * * This function can be used as a way of linking the npCommunicationId of * a Trophy Set to a titles npTitleId,but as with the other user based endpoints * in this version of the API you will only get a useful response back if the account * you are querying against has played the title. * * If you attempt to query a title ID which does not exist then a Resource not found error will be returned. * * There is a limit of 5 title IDs which can be included in the npTitleIds query. * Trying to include more than 5 will result in a Bad Request (query: npTitleId) error being returned. * * @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.npTitleIds The titleId can be a single title ID, or it can be a comma separated list of title IDs (%2C when used in a URL). Every title has an ID assigned to it with these typically starting "CUSA" for PS4 titles and "PPSA" for PS5 titles. * @param options.includeNotEarnedTrophyIds If optional parameter includeNotEarnedTrophyIds is included and set to true then the response will contain a list of IDs for the individual trophies which the user has not earned for each title ID queried. This functionality was added to the endpoint post release, most likely early 2023. * @param options.headerOverrides Override the headers in the request to the PSN API, such as to change the language. */ var getUserTrophiesForSpecificTitle = /*#__PURE__*/function () { var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, accountId, options) { var headerOverrides, args, url; return _regeneratorRuntime().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: headerOverrides = options.headerOverrides, args = _objectWithoutPropertiesLoose(options, _excluded); url = buildRequestUrl(TROPHY_BASE_URL, "/v1/users/:accountId/titles/trophyTitles", {}, _extends({ accountId: accountId }, args)); _context.next = 4; return call({ url: url, headers: headerOverrides }, authorization); case 4: return _context.abrupt("return", _context.sent); case 5: case "end": return _context.stop(); } }, _callee); })); return function getUserTrophiesForSpecificTitle(_x, _x2, _x3) { 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"; var USER_CPSS_BASE_URL = "https://m.np.playstation.com/api/cpss"; var USER_DMS_BASE_URL = "https://dms.api.playstation.com/api"; /** * A call to this function will retrieve the list of devices the client is logged into. * This includes information about PlayStation consoles (PS5, PS4, PS3) and handheld * devices (PSVita) that are associated with the account. * * @param authorization An object containing your access token, typically retrieved with `exchangeAccessCodeForAuthTokens()`. * @param options Optional - Additional headerOverride options to provide for the request */ var getAccountDevices = /*#__PURE__*/function () { var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authorization, options) { var queryParams, url, response, _response$error$messa, _response$error; return _regeneratorRuntime().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: queryParams = { includeFields: "device,systemData", platform: "PS5,PS4,PS3,PSVita" }; url = buildRequestUrl(USER_DMS_BASE_URL, "