@chez14/mal-api-lite
Version:
MyAnimeList API client, Lite Version
212 lines (205 loc) • 6.12 kB
JavaScript
'use strict';
var crypto = require('crypto');
var got = require('got');
var url = require('url');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var got__default = /*#__PURE__*/_interopDefault(got);
// src/client.ts
// src/constants.ts
var PKG_VERSION = "1.2.9";
// src/client.ts
var MALClient = class {
clientId;
clientSecret;
accessToken;
refreshToken;
got;
gotOAuth;
PKCEChallangeGenerateSize = 32;
userAgent = "@chez14/mal-api-lite";
malApiBaseUrl = "https://api.myanimelist.net/v2/";
malOAuthUrl = "https://myanimelist.net/v1/oauth2/";
/**
* Create MAL API Client
*
* @param param0 Your trusty configuration
*/
constructor({ clientId, clientSecret, accessToken, refreshToken, gotOptions, gotOAuthOptions }) {
if ((!clientSecret || !clientId) && !(accessToken || refreshToken)) {
throw new Error(
"You need to provide both (`clientSecret` and `clientId`) OR one of (`accessToken` or `refreshToken`)"
);
}
this.clientId = clientId;
this.clientSecret = clientSecret;
this.accessToken = accessToken;
this.refreshToken = refreshToken;
this.userAgent += ` v${PKG_VERSION}`;
this.got = got__default.default.extend({
prefixUrl: this.malApiBaseUrl,
responseType: "json",
headers: { "user-agent": this.userAgent },
hooks: {
beforeRequest: [
(options) => {
if (this.accessToken) {
options.headers.authorization = `Bearer ${this.accessToken}`;
} else {
options.headers["X-MAL-CLIENT-ID"] = this.clientId;
}
}
]
},
...gotOptions
});
this.gotOAuth = got__default.default.extend({
prefixUrl: this.malOAuthUrl,
headers: { "user-agent": this.userAgent },
responseType: "json",
...gotOAuthOptions
});
}
/**
* Get Access Token & Refresh Token from given Authorization Code.
*
* @param authCode Authorization code
* @param codeVerifier PKCE Code Challenge
* @param redirectUri Redirect url, specified on on previous step
*/
async resolveAuthCode(authCode, codeVerifier, redirectUri) {
if (!this.clientSecret || !this.clientId) {
throw new Error("clientSecret and clientId must be filled to use this function!");
}
const resp = await this.gotOAuth.post("token", {
form: {
client_id: this.clientId,
client_secret: this.clientSecret,
grant_type: "authorization_code",
code: authCode,
redirect_uri: redirectUri,
code_verifier: codeVerifier
}
});
const { access_token, refresh_token } = resp.body;
this.accessToken = access_token;
this.refreshToken = refresh_token;
return resp.body;
}
/**
* Generate OAuth URL to gain access to user account on MyAnimeList platform.
* Will require clientId and clientSecret from custructor.
*
* @param codeChallenge PKCE Code Challenge
* @param redirectUri If you have more than one Redirect URL, please specify
* the url you use.
* @param state Your app state
* @param codeChallengeMethod Only accept "plain". Don't change unless you
* know what you're doing!
*/
getOAuthURL(redirectUri, codeChallenge, state) {
if (!this.clientId) {
throw new Error("clientId must be filled to use this function!");
}
if (!codeChallenge) {
codeChallenge = crypto.randomBytes(this.PKCEChallangeGenerateSize).toString("base64url");
}
const query = {
response_type: "code",
client_id: this.clientId,
state,
redirect_uri: redirectUri,
code_challenge: codeChallenge,
code_challenge_method: "plain"
};
const urlBuilder = new url.URL("authorize", this.gotOAuth.defaults.options.prefixUrl);
Object.keys(query).forEach((key) => {
if (query[key]) {
urlBuilder.searchParams.append(key, query[key]);
}
});
return { url: urlBuilder.toString(), codeChallenge, state };
}
/**
* Refresh your access token with refresh token.
*
* @param refreshToken Custom refresh token
*/
async resolveRefreshToken(refreshToken) {
if (!refreshToken) {
refreshToken = this.refreshToken;
}
if (!refreshToken) {
throw Error("No refreshToken provided.");
}
const resp = await this.gotOAuth.post("token", {
form: {
client_id: this.clientId,
client_secret: this.clientSecret,
grant_type: "refresh_token",
refresh_token: refreshToken
}
});
const { access_token, refresh_token } = resp.body;
this.accessToken = access_token;
this.refreshToken = refresh_token;
return resp.body;
}
preprocessParam(param) {
if ((param == null ? void 0 : param.fields) && Array.isArray(param.fields)) {
param.fields = param.fields.join(",");
}
return param;
}
/**
* Do HTTP GET stuffs.
*
* @param resource Url to call
* @param param Parameter body
*/
async get(resource, param) {
param = this.preprocessParam(param);
const response = await this.got.get(resource, {
searchParams: param
});
return response.body;
}
/**
* Do HTTP POST stuffs.
*
* @param resource Url to call
* @param param Parameter body
*/
async post(resource, param) {
param = this.preprocessParam(param);
const response = await this.got.post(resource, {
form: param
});
return response.body;
}
/**
* Do HTTP PATCH stuffs.
*
* @param resource Url to call
* @param param Parameter body
*/
async patch(resource, param) {
param = this.preprocessParam(param);
const response = await this.got.patch(resource, {
form: param
});
return response.body;
}
/**
* Do HTTP DELETE stuffs.
*
* @param resource Url to call
* @param param Parameter body (discouraged)
*/
async delete(resource) {
const response = await this.got.delete(resource);
return response.body;
}
};
exports.MALClient = MALClient;
//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map