wiki-saikou
Version:
The library provides the out of box accessing to MediaWiki API in both browsers & Node.js, and the syntax is very similar to vanilla `new mw.Api()`. TypeScript definition included~
250 lines (245 loc) • 8.05 kB
JavaScript
'use strict';
const WikiSaikou = require('./shared/wiki-saikou.1DPaxo4l.cjs');
const plugins = require('fexios/plugins');
const fexios = require('fexios');
/**
* WikiSaikou
* @description Standalone MediaWiki API SDK with `mw.Api`-like API in any environments
* @author Dragon-Fish <dragon-fish@qq.com>
* @license MIT
*/
class MediaWikiApi extends WikiSaikou.WikiSaikouCore {
autoReloginEnabled = false;
loginCredentials;
constructor(configOrBaseURL, defaultOptions, defaultParams) {
const config = WikiSaikou.resolveLegacyCtor(
configOrBaseURL,
defaultOptions,
defaultParams
);
super(config);
this.request.plugin(plugins.pluginCookieJar);
this.request.on("beforeRequest", (ctx) => this.handleBeforeRequest(ctx));
this.request.on("afterResponse", (ctx) => this.handleAfterResponse(ctx));
}
canAutoRelogin() {
return Boolean(this.autoReloginEnabled && this.loginCredentials?.username);
}
getAssertUser() {
return this.loginCredentials?.username;
}
getAutoReloginRetries() {
return this.loginCredentials?.autoReloginRetries ?? 3;
}
getParam(data, key) {
if (!data) return void 0;
if (data instanceof URLSearchParams) {
return data.get(key);
}
if (typeof FormData !== "undefined" && data instanceof FormData) {
return data.get(key);
}
return data[key];
}
hasParam(data, key) {
if (!data) return false;
if (data instanceof URLSearchParams) {
return data.has(key);
}
if (typeof FormData !== "undefined" && data instanceof FormData) {
return data.has(key);
}
return data[key] !== void 0;
}
setParam(data, key, value) {
if (data instanceof URLSearchParams) {
data.set(key, value);
} else if (typeof FormData !== "undefined" && data instanceof FormData) {
data.set(key, value);
} else {
data[key] = value;
}
}
getAction(query, body) {
const action = this.getParam(query, "action") ?? this.getParam(body, "action");
return action === void 0 ? void 0 : String(action);
}
toStringArray(value) {
if (value === void 0 || value === null) return [];
if (Array.isArray(value)) {
return value.map((item) => String(item)).filter(Boolean);
}
return String(value).split("|").map((item) => item.trim()).filter(Boolean);
}
isLoginTokenRequest(query, body) {
const check = (data) => {
if (!data) return false;
const action = this.getParam(data, "action");
if (action && String(action) !== "query") return false;
if (!action) return false;
const meta = this.toStringArray(this.getParam(data, "meta"));
if (!meta.includes("tokens")) return false;
const types = this.toStringArray(this.getParam(data, "type"));
return types.includes("login");
};
return check(query) || check(body);
}
shouldSkipAutoRelogin(query, body) {
const action = this.getAction(query, body);
if (action === "login") return true;
if (this.isLoginTokenRequest(query, body)) {
return true;
}
return false;
}
isAssertUserFailed(data) {
const isAssertFailedCode = (code) => code === "assertuserfailed" || code === "assertnameduserfailed";
if (WikiSaikou.MediaWikiApiError.is(data)) {
return data.errors.some((error) => isAssertFailedCode(error.code));
}
return WikiSaikou.WikiSaikouError.extractMediaWikiApiErrors(data).some(
(error) => isAssertFailedCode(error.code)
);
}
async reloginIfNeeded() {
if (!this.canAutoRelogin() || !this.loginCredentials) return;
await this.login(
this.loginCredentials.lgname,
this.loginCredentials.lgpassword,
void 0,
{
autoRelogin: true,
autoReloginRetries: this.loginCredentials.autoReloginRetries
}
);
}
get cookieJar() {
return this.request.cookieJar;
}
handleBeforeRequest(ctx) {
if (!this.canAutoRelogin()) return ctx;
const { query, body } = ctx.request;
if (this.shouldSkipAutoRelogin(query, body)) return ctx;
if (this.hasParam(query, "assertuser") || this.hasParam(body, "assertuser")) {
return ctx;
}
const assertUser = this.getAssertUser();
if (body !== void 0 && body !== null) {
this.setParam(body, "assertuser", assertUser);
} else {
if (!ctx.request.query) {
ctx.request.query = {};
}
this.setParam(ctx.request.query, "assertuser", assertUser);
}
return ctx;
}
async handleAfterResponse(ctx) {
if (!this.canAutoRelogin()) return ctx;
const { query, body } = ctx.request;
if (this.shouldSkipAutoRelogin(query, body)) {
return ctx;
}
if (!this.hasParam(query, "assertuser") && !this.hasParam(body, "assertuser")) {
return ctx;
}
if (!this.isAssertUserFailed(ctx.data)) return ctx;
const attempt = Number(ctx.runtime.customEnv?.autoReloginAttempt ?? 0);
const maxAttempts = this.getAutoReloginRetries();
if (attempt >= maxAttempts) return ctx;
await this.reloginIfNeeded();
const { rawRequest, ...requestOptions } = ctx.request;
const nextEnv = {
...ctx.runtime.customEnv,
autoReloginAttempt: attempt + 1
};
const retryResponse = await this.request.request({
...requestOptions,
url: ctx.request.url,
customEnv: nextEnv
});
return retryResponse ?? ctx;
}
async login(lgname, lgpassword, params, postOptions) {
this.config.fexiosConfigs.credentials = "include";
const {
autoRelogin = true,
autoReloginRetries = 3,
...tokenOptions
} = postOptions || {};
if (tokenOptions.noCache === void 0) {
tokenOptions.noCache = true;
}
const res = await this.postWithToken(
"login",
{
action: "login",
lgname,
lgpassword,
...params
},
{
tokenName: "lgtoken",
...tokenOptions
}
);
const data = res?.data;
if (data?.login?.result !== "Success") {
throw new WikiSaikou.WikiSaikouError(
WikiSaikou.WikiSaikouErrorCode.LOGIN_FAILED,
data?.login?.reason?.text || data?.login?.result || "Login failed with unknown reason",
data
);
}
if (autoRelogin === true) {
this.autoReloginEnabled = true;
this.loginCredentials = {
lgname,
lgpassword,
username: data?.login?.lgusername,
autoReloginRetries: Number.isFinite(autoReloginRetries) && autoReloginRetries >= 0 ? Math.floor(autoReloginRetries) : 3
};
} else if (autoRelogin === false) {
this.autoReloginEnabled = false;
this.loginCredentials = void 0;
}
return data.login;
}
async logout() {
this.autoReloginEnabled = false;
this.loginCredentials = void 0;
await this.postWithToken("csrf", {
action: "logout"
}).catch(() => {
});
this.tokens.clear();
this.request.cookieJar?.clear();
}
}
exports.MediaWikiApiError = WikiSaikou.MediaWikiApiError;
exports.MwApiBase = WikiSaikou.WikiSaikouCore;
Object.defineProperty(exports, "MwParamNormalizer", {
enumerable: true,
get: function () { return WikiSaikou.MwParamNormalizer; }
});
exports.WikiSaikouCore = WikiSaikou.WikiSaikouCore;
Object.defineProperty(exports, "WikiSaikouError", {
enumerable: true,
get: function () { return WikiSaikou.WikiSaikouError; }
});
exports.WikiSaikouErrorCode = WikiSaikou.WikiSaikouErrorCode;
exports.createFexiosSaikou = WikiSaikou.createFexiosSaikou;
exports.CookieJar = plugins.CookieJar;
exports.MediaWikiApi = MediaWikiApi;
exports.MediaWikiNodeClient = MediaWikiApi;
exports.MwApi = MediaWikiApi;
Object.prototype.hasOwnProperty.call(fexios, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: fexios['__proto__']
});
Object.keys(fexios).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = fexios[k];
});
//# sourceMappingURL=node.cjs.map