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~
1,142 lines (1,141 loc) • 36.5 kB
JavaScript
function N(o) {
if (typeof globalThis.structuredClone == "function")
try {
return globalThis.structuredClone(o);
} catch {
}
return S(o, /* @__PURE__ */ new WeakMap());
}
function S(o, t) {
if (typeof o != "object" || o === null) return o;
const e = t.get(o);
if (e) return e;
if (o instanceof Date) return new Date(o.getTime());
if (o instanceof RegExp)
return new RegExp(o.source, o.flags);
if (o instanceof URL) return new URL(o.toString());
if (o instanceof URLSearchParams)
return new URLSearchParams(o.toString());
if (o instanceof ArrayBuffer) return o.slice(0);
if (ArrayBuffer.isView(o)) {
if (o instanceof DataView)
return new DataView(
o.buffer.slice(0),
o.byteOffset,
o.byteLength
);
const a = o, f = a.constructor;
return new f(a.buffer.slice(0), a.byteOffset, a.length);
}
if (o instanceof Map) {
const a = /* @__PURE__ */ new Map();
return t.set(o, a), o.forEach((f, i) => {
a.set(S(i, t), S(f, t));
}), a;
}
if (o instanceof Set) {
const a = /* @__PURE__ */ new Set();
return t.set(o, a), o.forEach((f) => a.add(S(f, t))), a;
}
if (Array.isArray(o)) {
const a = new Array(o.length);
t.set(o, a);
for (let f = 0; f < a.length; f++)
a[f] = S(o[f], t);
return a;
}
const s = Object.getPrototypeOf(o), r = Object.create(s);
t.set(o, r);
const n = Object.getOwnPropertyDescriptors(o);
for (const a of Reflect.ownKeys(n)) {
const f = n[a];
"value" in f && (f.value = S(f.value, t)), Object.defineProperty(r, a, f);
}
return r;
}
function b(o) {
if (typeof o != "object" || o === null)
return !1;
const t = Object.getPrototypeOf(o);
return t === Object.prototype || t === null;
}
const v = function(o) {
const t = this.constructor.prototype, e = Reflect.get(t, o, t);
function s(...r) {
return Reflect.apply(e, s, r);
}
Reflect.setPrototypeOf(s, t);
for (const r of Reflect.ownKeys(e)) {
const n = Reflect.getOwnPropertyDescriptor(e, r);
n && Reflect.defineProperty(s, r, n);
}
return s;
};
v.prototype = Object.create(Function.prototype);
const G = v;
function E(o, ...t) {
const e = N(o || {});
for (const s of t)
if (s != null)
for (const r of Reflect.ownKeys(s)) {
const n = s[r];
if (typeof n > "u") continue;
if (n === null) {
delete e[r];
continue;
}
const a = e[r];
b(a) && b(n) ? e[r] = E(a, n) : e[r] = N(n);
}
return e;
}
var R = /* @__PURE__ */ ((o) => (o.BODY_USED = "BODY_USED", o.NO_BODY_READER = "NO_BODY_READER", o.TIMEOUT = "TIMEOUT", o.NETWORK_ERROR = "NETWORK_ERROR", o.BODY_NOT_ALLOWED = "BODY_NOT_ALLOWED", o.HOOK_CONTEXT_CHANGED = "HOOK_CONTEXT_CHANGED", o.ABORTED_BY_HOOK = "ABORTED_BY_HOOK", o.INVALID_HOOK_CALLBACK = "INVALID_HOOK_CALLBACK", o.UNEXPECTED_HOOK_RETURN = "UNEXPECTED_HOOK_RETURN", o.UNSUPPORTED_RESPONSE_TYPE = "UNSUPPORTED_RESPONSE_TYPE", o.FEATURE_MOVED_TO_PLUGIN = "FEATURE_MOVED_TO_PLUGIN", o.BODY_TRANSFORM_ERROR = "BODY_TRANSFORM_ERROR", o))(R || {});
class m extends Error {
constructor(t, e, s, r) {
super(e, r), this.code = t, this.context = s;
}
name = "FexiosError";
static is(t, e) {
return !(t instanceof m) || t instanceof C ? !1 : e ? t.code === e : !0;
}
}
class C extends m {
constructor(t, e, s) {
super(e.statusText, t, void 0, s), this.response = e;
}
name = "FexiosResponseError";
static is(t) {
return t instanceof C;
}
}
const J = (o) => m.is(o);
var w;
((o) => {
o.makeSearchParams = (a) => {
if (!a)
return new URLSearchParams();
if (a instanceof URLSearchParams)
return a;
if (typeof a != "object" || a?.constructor !== Object)
throw new TypeError("only plain object is supported");
const f = new URLSearchParams(), i = (l, h) => {
h != null && f.append(l, h);
}, c = (l, h) => {
h != null && f.set(l, h);
}, u = (l, h) => {
if (h != null) {
if (Array.isArray(h)) {
for (const d of h) i(l, d?.toString());
return;
}
if (typeof h == "object" && h.constructor === Object) {
for (const [d, p] of Object.entries(h)) {
if (p == null) continue;
const U = d.endsWith("[]"), D = U ? d.slice(0, -2) : d, O = `${l}[${D}]`;
if (U) {
const q = `${O}[]`;
if (Array.isArray(p))
for (const A of p) i(q, A?.toString());
else typeof p == "object" && p !== null && p.constructor === Object ? u(`${O}[]`, p) : i(q, p?.toString());
} else if (Array.isArray(p))
for (const q of p) i(O, q?.toString());
else typeof p == "object" && p !== null && p.constructor === Object ? u(O, p) : c(O, p?.toString());
}
return;
}
c(l, h?.toString());
}
};
for (const [l, h] of Object.entries(a))
u(l, h);
return f;
}, o.makeQueryString = (a) => (0, o.makeSearchParams)(a).toString(), o.makeURL = (a, f, i, c) => {
const u = typeof window < "u" && window.location?.origin || "http://localhost", l = typeof a == "string" ? new URL(a, c ?? u) : new URL(a), h = (0, o.toQueryRecord)(l.searchParams), d = (0, o.mergeQueries)(h, f || {}), p = (0, o.makeSearchParams)(d);
return l.search = p.toString(), typeof i < "u" && (l.hash = i), l;
};
const t = /\[([^\]]*)\]/g;
function e(a) {
if (!a.includes("[")) return { path: [a], forceArray: !1 };
const i = [a.slice(0, a.indexOf("["))];
t.lastIndex = 0;
let c, u = !1, l = !1;
for (; c = t.exec(a); )
c[1] === "" ? (u = !0, l = !0) : (i.push(c[1]), l = !1);
return u && l && (i[i.length - 1] = i[i.length - 1] + "[]"), { path: i, forceArray: u };
}
function s(a, f, i, c) {
let u = a;
for (let h = 0; h < f.length - 1; h++) {
const d = f[h];
(u[d] === void 0 || typeof u[d] != "object" || Array.isArray(u[d])) && (u[d] = {}), u = u[d];
}
const l = f[f.length - 1];
u[l] === void 0 ? u[l] = c ? [i] : i : Array.isArray(u[l]) ? u[l].push(i) : u[l] = [u[l], i];
}
o.toQueryRecord = (a) => {
typeof a == "string" && (a = (0, o.fromString)(a));
const f = {};
for (const [i, c] of a.entries()) {
const { path: u, forceArray: l } = e(String(i));
s(f, u, c?.toString(), l);
}
return f;
}, o.fromString = (a) => {
const f = a.trim();
if (!f) return new URLSearchParams();
if (f.startsWith("?")) return new URLSearchParams(f.slice(1));
const i = f.indexOf("?");
if (i >= 0) {
const c = f.indexOf("#", i + 1), u = f.slice(i + 1, c >= 0 ? c : void 0);
return new URLSearchParams(u);
}
return new URLSearchParams(f);
}, o.mergeQueries = (...a) => {
const f = {};
for (const i of a)
i != null && n(f, r(i));
return f;
};
function r(a) {
if (!a) return {};
if (a instanceof URLSearchParams || a instanceof FormData || a instanceof Map)
return (0, o.toQueryRecord)(a);
if (typeof a == "string") return (0, o.toQueryRecord)((0, o.fromString)(a));
if (b(a)) return a;
throw new TypeError(
`unsupported type transformation, got: ${Object.prototype.toString.call(
a
)}`
);
}
function n(a, f) {
for (const [i, c] of Object.entries(f)) {
if (c === void 0) continue;
if (c === null) {
delete a[i];
continue;
}
const u = a[i];
b(u) && b(c) ? n(u, c) : a[i] = N(c);
}
}
})(w || (w = {}));
class M {
constructor(t, e, s) {
this.rawResponse = t, this.data = e, this.responseType = s, ["ok", "status", "statusText", "headers", "url", "redirected"].forEach(
(r) => {
Reflect.defineProperty(this, r, {
get: () => t[r]
});
}
);
}
ok;
status;
statusText;
headers;
url;
redirected;
}
const V = (o) => {
if (o) {
if (o.includes("application/json") || o.endsWith("+json"))
return "json";
if (o.startsWith("text/")) return "text";
if (o.includes("multipart/form-data") || o.includes("application/x-www-form-urlencoded"))
return "form";
if (/^image\//.test(o) || /^video\//.test(o) || /^audio\//.test(o) || o.includes("application/pdf"))
return "blob";
if (o.includes("application/octet-stream") || o.includes("application/zip") || o.includes("application/x-tar") || o.includes("application/x-7z-compressed") || o.includes("application/x-gzip"))
return "arrayBuffer";
}
};
async function K(o, t, e, s) {
const r = o.clone(), n = o.headers.get("content-type")?.toLowerCase() ?? "", a = o.headers.get("upgrade")?.toLowerCase(), f = o.headers.get("connection")?.toLowerCase();
if (t === "ws" || t === "stream")
throw new m(
R.FEATURE_MOVED_TO_PLUGIN,
`responseType "${String(
t
)}" has been moved to plugins. Use "fexios/plugins" (fx.plugin(pluginWebSocket) / fx.plugin(pluginSSE)) and call fx.ws()/fx.sse() instead.`
);
if (a === "websocket" && f === "upgrade")
throw new m(
R.FEATURE_MOVED_TO_PLUGIN,
'WebSocket upgrade response detected. WebSocket support has been moved to plugins. Please use "fexios/plugins" and call fx.ws().'
);
if (n.includes("text/event-stream"))
throw new m(
R.FEATURE_MOVED_TO_PLUGIN,
'SSE (text/event-stream) response detected. SSE support has been moved to plugins. Please use "fexios/plugins" and call fx.sse().'
);
let i = t ?? V(n) ?? "text", c;
try {
if (i === "form")
c = await r.formData();
else if (i === "arrayBuffer")
c = await r.arrayBuffer();
else if (i === "blob")
c = await r.blob();
else if (i === "json") {
const h = await r.text();
c = h ? JSON.parse(h) : null;
} else if (i === "text") {
const h = await r.text();
if (t)
c = h;
else {
const d = h.trim();
if (d.startsWith("{") && d.endsWith("}") || d.startsWith("[") && d.endsWith("]"))
try {
c = JSON.parse(d), i = "json";
} catch {
c = h;
}
else
c = h;
}
} else {
const h = await r.arrayBuffer();
c = new Uint8Array(h);
}
} catch (h) {
if (!(h instanceof Error)) throw h;
try {
c = await r.text(), i = "text";
} catch {
throw new m(
R.BODY_TRANSFORM_ERROR,
`Failed to transform response body to ${i}`,
void 0,
{ cause: h }
);
}
}
const u = new M(
o,
c,
i
), l = e?.(u);
if (typeof l == "boolean" ? l : !u.ok)
throw new C(u.statusText, u);
return u;
}
var k;
((o) => {
o.makeHeaders = (t) => {
if (!t) return new Headers();
if (t instanceof Headers) return new Headers(t);
const e = new Headers();
if (t instanceof Map) {
for (const [s, r] of t.entries())
if (r != null)
if (Array.isArray(r))
for (const n of r)
n != null && e.append(s, String(n));
else
e.append(s, String(r));
return e;
}
if (b(t)) {
for (const [s, r] of Object.entries(t))
if (r != null)
if (Array.isArray(r))
for (const n of r)
n != null && e.append(s, String(n));
else
e.append(s, String(r));
return e;
}
throw new TypeError(
"only plain object, Map/ReadonlyMap, or Headers is supported"
);
}, o.toHeaderRecord = (t) => {
if (t instanceof Headers) {
const e = {};
return t.forEach((s, r) => {
e[r] = e[r] ? [...e[r], s] : [s];
}), e;
}
if (t instanceof Map) {
const e = {};
for (const [s, r] of t.entries())
if (r != null)
if (Array.isArray(r)) {
const n = r.filter((a) => a != null).map((a) => String(a));
n.length && (e[s] = (e[s] ?? []).concat(n));
} else {
const n = String(r);
e[s] = e[s] ? [...e[s], n] : [n];
}
return e;
}
throw new TypeError(
`unsupported type transformation, got: ${Object.prototype.toString.call(
t
)}`
);
}, o.mergeHeaders = (...t) => {
const e = new Headers(), s = (r) => {
for (const [n, a] of Object.entries(r))
if (a !== void 0) {
if (a === null) {
e.delete(n);
continue;
}
if (Array.isArray(a)) {
e.delete(n);
for (const f of a)
f != null && e.append(n, String(f));
} else
e.set(n, String(a));
}
};
for (const r of t) {
if (r == null) continue;
if (r instanceof Headers) {
r.forEach((a, f) => {
e.set(f, a);
});
continue;
}
if (b(r)) {
s(r);
continue;
}
const n = (0, o.toHeaderRecord)(r);
for (const [a, f] of Object.entries(n)) {
e.delete(a);
for (const i of f) e.append(a, i);
}
}
return e;
};
})(k || (k = {}));
class g extends G {
static version = "6.2.1";
static FINAL_SYMBOL = /* @__PURE__ */ Symbol("FEXIOS_FINAL_CONTEXT");
baseConfigs;
// for axios compatibility
get defaults() {
return this.baseConfigs;
}
set defaults(t) {
this.baseConfigs = t;
}
static DEFAULT_CONFIGS = {
baseURL: "",
timeout: 0,
credentials: void 0,
headers: {},
query: {},
responseType: void 0,
shouldThrow(t) {
return !t.ok;
},
fetch: globalThis.fetch
};
hooks = [];
static ALL_METHODS = [
"get",
"post",
"put",
"patch",
"delete",
"head",
"options",
"trace"
];
static METHODS_WITHOUT_BODY = [
"get",
"head",
"options",
"trace"
];
constructor(t = {}) {
super("request"), this.baseConfigs = E(g.DEFAULT_CONFIGS, t), g.ALL_METHODS.forEach(
(e) => this.createMethodShortcut(e.toLowerCase())
);
}
attachLegacyAliases(t) {
const e = () => t.request, s = () => t.runtime, r = (n, a) => {
try {
Object.defineProperty(t, n, { configurable: !0, ...a });
} catch {
}
};
r("url", {
get: () => e().url,
set: (n) => {
e().url = n?.toString?.() ?? String(n);
}
}), r("method", {
get: () => e().method,
set: (n) => e().method = n
}), r("headers", {
get: () => e().headers,
set: (n) => e().headers = n
}), r("query", { get: () => e().query, set: (n) => e().query = n }), r("body", { get: () => e().body, set: (n) => e().body = n }), r("baseURL", {
get: () => e().baseURL,
set: (n) => e().baseURL = n
}), r("timeout", {
get: () => e().timeout,
set: (n) => e().timeout = n
}), r("credentials", {
get: () => e().credentials,
set: (n) => e().credentials = n
}), r("cache", { get: () => e().cache, set: (n) => e().cache = n }), r("mode", { get: () => e().mode, set: (n) => e().mode = n }), r("fetch", { get: () => e().fetch, set: (n) => e().fetch = n }), r("shouldThrow", {
get: () => e().shouldThrow,
set: (n) => e().shouldThrow = n
}), r("responseType", {
get: () => e().responseType,
set: (n) => e().responseType = n
}), r("abortController", {
get: () => s().abortController,
set: (n) => s().abortController = n
}), r("customEnv", {
get: () => s().customEnv,
set: (n) => s().customEnv = n
}), r("rawRequest", {
get: () => e().rawRequest,
set: (n) => e().rawRequest = n
}), r("data", {
get: () => t.response ? t.response.data : void 0,
set: (n) => {
t.response && (t.response.data = n);
}
});
}
finalizeContext(t, e) {
const s = t.response, r = s?.rawResponse ?? t.rawResponse, n = t.request;
Object.defineProperties(t, {
url: { get: () => r?.url || e },
data: { get: () => s.data },
headers: { get: () => r.headers },
responseType: { get: () => s.responseType },
rawRequest: { get: () => n.rawRequest }
});
}
async request(t, e) {
const s = this;
let r = e || {};
typeof t == "string" || t instanceof URL ? r = { ...e || {}, url: t } : typeof t == "object" && (r = t);
const {
abortController: n,
customEnv: a,
...f
} = r;
let i = {
get app() {
return s;
},
request: {
...f,
url: r.url?.toString?.() ?? String(r.url)
},
runtime: {
abortController: n,
customEnv: a
},
response: void 0,
rawResponse: void 0,
// legacy fields are attached via defineProperty
url: "",
headers: {},
query: {}
};
if (this.attachLegacyAliases(i), i = await this.emit("beforeInit", i), i[g.FINAL_SYMBOL]) return i;
if ("customEnv" in this.baseConfigs && (i.runtime.customEnv = E(
{},
// ensure we don't mutate baseConfigs
this.baseConfigs.customEnv,
i.runtime.customEnv
)), i.request = this.applyDefaults(i.request), g.METHODS_WITHOUT_BODY.includes(
i.request.method?.toLocaleLowerCase?.()
) && i.request.body)
throw new m(
R.BODY_NOT_ALLOWED,
`Request method "${i.request.method}" does not allow body`
);
if (i = await this.emit("beforeRequest", i), i[g.FINAL_SYMBOL]) return i;
let c;
const u = {}, l = i.request;
if (typeof l.body < "u" && l.body !== null && (l.body instanceof Blob || l.body instanceof FormData || l.body instanceof URLSearchParams ? c = l.body : typeof l.body == "object" && l.body !== null ? (c = JSON.stringify(l.body), l.headers = this.mergeHeaders(l.headers, {
"Content-Type": "application/json"
})) : c = l.body), !k.makeHeaders(l.headers || {}).get("content-type") && c && (c instanceof FormData || c instanceof URLSearchParams ? u["content-type"] = null : typeof c == "string" && typeof l.body == "object" ? u["content-type"] = "application/json" : c instanceof Blob && (u["content-type"] = c.type || "application/octet-stream")), l.body = c, i = await this.emit("afterBodyTransformed", i), i[g.FINAL_SYMBOL]) return i;
const d = i.runtime.abortController ?? (globalThis.AbortController ? new AbortController() : void 0), p = globalThis.location?.href || "http://localhost", U = new URL(
i.request.baseURL || this.baseConfigs.baseURL || p,
p
), D = new URL(i.request.url, U), O = w.makeURL(
D,
i.request.query,
D.hash
// 保留 hash
).toString(), q = new Request(O, {
method: i.request.method || "GET",
credentials: i.request.credentials,
cache: i.request.cache,
mode: i.request.mode,
headers: k.mergeHeaders(
this.baseConfigs.headers,
i.request.headers || {},
u
),
body: i.request.body,
signal: d?.signal
});
if (i.request.rawRequest = q, i = await this.emit("beforeActualFetch", i), i[g.FINAL_SYMBOL]) return i;
const A = i.request.timeout ?? this.baseConfigs.timeout ?? 60 * 1e3, $ = i.request.shouldThrow ?? this.baseConfigs.shouldThrow;
if (i.request.url.startsWith("ws") || i.request.responseType === "ws")
throw new m(
R.FEATURE_MOVED_TO_PLUGIN,
'WebSocket support has been moved to plugins. Use "fexios/plugins" and call fx.ws() instead.',
i
);
if (i.request.responseType === "stream")
throw new m(
R.FEATURE_MOVED_TO_PLUGIN,
'SSE support has been moved to plugins. Use "fexios/plugins" and call fx.sse() instead.',
i
);
let L;
try {
d && (L = A > 0 ? setTimeout(() => {
d.abort();
}, A) : void 0);
const B = await (i.request.fetch || this.baseConfigs.fetch || globalThis.fetch)(i.request.rawRequest).catch(
(F) => {
throw L && clearTimeout(L), d?.signal.aborted ? new m(
R.TIMEOUT,
`Request timed out after ${A}ms`,
i
) : new m(
R.NETWORK_ERROR,
F.message,
i
);
}
);
return L && clearTimeout(L), i.rawResponse = B, await this.emit("afterRawResponse", i), i[g.FINAL_SYMBOL] ? i : (i.response = await K(
B,
i.request.responseType,
$,
A
), i.rawResponse = i.response.rawResponse, this.finalizeContext(i, O), this.emit("afterResponse", i));
} catch (H) {
throw L && clearTimeout(L), H;
}
}
mergeQueries = w.mergeQueries;
mergeHeaders = k.mergeHeaders;
applyDefaults(t) {
const e = t, s = globalThis.location?.href || "http://localhost", r = e.baseURL || this.baseConfigs.baseURL || s, n = new URL(r, s), a = new URL(e.url.toString(), n), f = w.toQueryRecord(
n.searchParams
), i = w.toQueryRecord(
a.searchParams
), c = w.mergeQueries(
f,
i
);
a.search = w.makeSearchParams(c).toString(), e.url = a.toString();
const u = w.mergeQueries(
this.baseConfigs.query,
e.query
);
return e.query && this.restoreNulls(u, e.query), e.query = u, e;
}
restoreNulls(t, e) {
if (!(!e || typeof e != "object"))
for (const [s, r] of Object.entries(e))
r === null ? t[s] = null : b(r) && ((!t[s] || typeof t[s] != "object") && (t[s] = {}), this.restoreNulls(t[s], r));
}
isFinalContextLike(t) {
if (!t || typeof t != "object") return !1;
const e = t.request, s = t.response, r = t.rawResponse;
return !e || !s || !r || typeof e.url != "string" ? !1 : r instanceof Response || s?.rawResponse instanceof Response || s?.rawResponse?.constructor?.name === "Response";
}
async resolveShortCircuit(t, e, s) {
const r = t;
let n;
if (e instanceof M ? (n = e, r.rawResponse = n.rawResponse) : (r.rawResponse = e, n = await K(
e,
t.request?.responseType,
t.request?.shouldThrow ?? this.baseConfigs.shouldThrow,
t.request?.timeout ?? this.baseConfigs.timeout ?? 60 * 1e3
)), r.response = n, r.rawResponse = n.rawResponse, !r.request?.rawRequest)
try {
r.request.rawRequest = new Request(r.request.url, {
method: r.request.method || "GET",
headers: r.request.headers,
body: r.request.body
});
} catch {
}
if (this.finalizeContext(r, n.rawResponse?.url || ""), s !== "afterResponse") {
const a = await this.emit("afterResponse", r);
return a[g.FINAL_SYMBOL] = !0, a;
} else
return r[g.FINAL_SYMBOL] = !0, r;
}
async emit(t, e, s = {
shouldHandleShortCircuitResponse: !0
}) {
const r = this.hooks.filter((n) => n.event === t);
if (r.length === 0) return e;
for (let n = 0; n < r.length; n++) {
const a = r[n], f = `${String(t)}#${a.action.name || `anonymous#${n}`}`, i = /* @__PURE__ */ Symbol("FEXIOS_HOOK_CTX_MARK");
try {
e[i] = i;
} catch {
}
const c = await a.action.call(this, e), u = c === e, l = c && typeof c == "object" && c[i] === i;
try {
delete e[i];
} catch {
}
if (c === !1)
throw new m(
R.ABORTED_BY_HOOK,
`Request aborted by hook "${f}"`,
e
);
if (u || l) {
e = c;
continue;
}
if (this.isFinalContextLike(c))
return c[g.FINAL_SYMBOL] = !0, c;
if (c instanceof M)
return this.resolveShortCircuit(e, c, t);
if (c instanceof Response) {
if (s.shouldHandleShortCircuitResponse !== !1)
return this.resolveShortCircuit(e, c, t);
e.rawResponse = c;
}
}
return e;
}
on(t, e, s = !1) {
if (typeof e != "function")
throw new m(
R.INVALID_HOOK_CALLBACK,
`Hook should be a function, but got "${typeof e}"`
);
return this.hooks[s ? "unshift" : "push"]({
event: t,
action: e
}), this;
}
off(t, e) {
return t === "*" || !t ? this.hooks = this.hooks.filter((s) => s.action !== e) : this.hooks = this.hooks.filter(
(s) => s.event !== t || s.action !== e
), this;
}
createInterceptor(t) {
return {
handlers: () => this.hooks.filter((e) => e.event === t).map((e) => e.action),
use: (e, s = !1) => this.on(t, e, s),
clear: () => {
this.hooks = this.hooks.filter((e) => e.event !== t);
}
};
}
interceptors = {
request: this.createInterceptor("beforeRequest"),
response: this.createInterceptor("afterResponse")
};
createMethodShortcut(t) {
return Reflect.defineProperty(this, t, {
get: () => (e, s, r) => (g.METHODS_WITHOUT_BODY.includes(
t.toLocaleLowerCase()
) ? r = s : (r = r || {}, r.body = s), this.request(e, {
...r,
method: t
}))
}), this;
}
extends(t) {
const e = new g(E(this.baseConfigs, t));
return e.hooks = [...this.hooks], e._plugins = new Map(this._plugins), e._plugins.forEach(async (s) => {
await e.plugin(s);
}), e;
}
create = g.create;
static create(t) {
return new g(t);
}
_plugins = /* @__PURE__ */ new Map();
plugin(t) {
if (typeof t?.name == "string" && typeof t?.install == "function") {
if (this._plugins.has(t.name))
return this;
const e = t.install(this);
if (this._plugins.set(t.name, t), e instanceof g)
return e;
}
return this;
}
uninstall(t) {
return typeof t == "string" && (t = this._plugins.get(t)), t && (t?.uninstall?.(this), this._plugins.delete(t.name)), this;
}
// 版本弃子们.jpg
/** @deprecated Use `mergeQueries` instead */
mergeQuery = this.mergeQueries;
}
const z = g.create, Z = z();
var P;
((o) => {
function t(s) {
return Array.isArray(s) ? s.join("|") : typeof s == "boolean" || s === null ? s ? "1" : void 0 : typeof s == "number" ? "" + s : s;
}
o.normalizeParamValue = t;
function e(s) {
const r = (a) => a && (a instanceof URLSearchParams || a instanceof FormData);
if (s == null)
return;
const n = new FormData();
if (r(s))
return s.forEach((a, f) => {
const i = t(a);
i != null && n.append(f, i);
}), n;
if (b(s))
return Object.entries(s).forEach(([a, f]) => {
const i = t(f);
i != null && n.append(a, i);
}), n;
}
o.normalizeBody = e;
})(P || (P = {}));
var I = /* @__PURE__ */ ((o) => (o.HTTP_ERROR = "HTTP_ERROR", o.LOGIN_FAILED = "LOGIN_FAILED", o.LOGIN_RETRY_LIMIT_EXCEEDED = "LOGIN_RETRY_LIMIT_EXCEEDED", o.TOKEN_RETRY_LIMIT_EXCEEDED = "TOKEN_RETRY_LIMIT_EXCEEDED", o))(I || {});
class y extends Error {
constructor(t, e = "", s) {
super(), this.code = t, this.message = e, this.cause = s, this.name = "WikiSaikouError";
}
static is(t, e) {
return t instanceof this && (e === void 0 || t.code === e);
}
}
class T extends Error {
constructor(t, e) {
super(), this.errors = t, this.cause = e, this.name = "MediaWikiApiError", this.errors = T.normalizeErrors(t), this.message = t.map((s) => s.text).filter(Boolean).join(`
`), this.code = this.isBadTokenError() ? "badtoken" : this.errors[0]?.code || "Unknown Error";
}
get firstError() {
return this.errors[0];
}
isBadTokenError() {
return this.errors.some((t) => t.code === "badtoken") || ["NeedToken", "WrongToken"].includes(this.cause?.data?.login?.result);
}
toString() {
return `[${this.name} ${this.code}]`;
}
static is(t) {
return t instanceof this;
}
static normalizeErrors(t) {
return Array.isArray(t) === !1 ? [] : t.filter((e) => typeof e == "object" && !!e?.code).map((e) => e.text ? e : e.info ? { ...e, text: e.info } : e["*"] ? { ...e, text: e["*"] } : { ...e, text: "" });
}
}
((o) => {
function t(n) {
if (n == null) return;
if (n?.response?.data !== void 0) return n.response.data;
if (n?.data !== void 0) return n.data;
const a = n instanceof Error ? n.cause : void 0;
return a?.response?.data !== void 0 ? a.response.data : a?.data !== void 0 ? a.data : n || void 0;
}
function e(n) {
return s(n).length > 0;
}
o.includesMediaWikiApiError = e, o.normalizeMwApiErrors = T.normalizeErrors;
function s(n) {
let a = t(n);
if (typeof a != "object" || a === null)
return [];
const f = a?.error, i = a?.errors, c = [];
return f && c.push(f), Array.isArray(i) && c.push(...i), (0, o.normalizeMwApiErrors)(c);
}
o.extractMediaWikiApiErrors = s;
function r(n) {
if (T.is(n))
return n.isBadTokenError();
{
const a = s(n);
return new T(a).isBadTokenError();
}
}
o.isBadTokenError = r;
})(y || (y = {}));
const Y = /* @__PURE__ */ Symbol.for("__FEXIOS_SAIKOU__");
function W(o) {
const t = o instanceof g ? o : new g({
baseURL: o instanceof URL ? o.toString() : String(o),
responseType: "json"
});
return t[Y] || (Reflect.defineProperty(t, Y, {
get: () => !0,
enumerable: !1,
configurable: !1
}), t.on("beforeInit", (e) => {
if (e.request.method?.toLowerCase() !== "post")
return e;
if (e.request.body === void 0 || e.request.body === null)
return e.request.body = void 0, e;
const s = e.request.body = P.normalizeBody(
e.request.body
), r = new URLSearchParams(e.request.query);
return s.has("format") && r.delete("format"), s.has("formatversion") && r.delete("formatversion"), s.has("action") && r.delete("action"), s.has("origin") && (r.set("origin", "" + s.get("origin")), s.delete("origin")), e.request.query = Object.fromEntries(r.entries()), e;
}), t.on("beforeInit", (e) => (e.request.query = w.mergeQueries(
{},
P.normalizeBody(e.request.query)
), e)), t.on("beforeRequest", (e) => {
const s = new URL(e.request.url), r = w.mergeQueries(s.searchParams, e.query);
if (globalThis.location && (!r.origin && location.origin !== s.origin ? (r.origin = location.origin, t.baseConfigs.credentials = "include", t.baseConfigs.mode = "cors") : location.origin === s.origin && (delete r.origin, t.baseConfigs.credentials = void 0, t.baseConfigs.mode = void 0)), r.origin) {
const n = encodeURIComponent(r.origin).replace(/\./g, "%2E");
delete r.origin, e.request.query = r, e.request.url = `${s.origin}${s.pathname}?origin=${n}`;
} else
e.request.query = r;
return e;
}), t._tokens = /* @__PURE__ */ new Map(), t.on("afterResponse", (e) => {
const { data: s } = e, r = e.runtime.customEnv?.mwTokenName;
r && y.isBadTokenError(s) && t._tokens.delete(r);
const n = s?.query?.tokens;
n && typeof n == "object" && Object.entries(n).forEach(([f, i]) => {
typeof i == "string" && t._tokens.set(f.replace(/token$/i, "").toLowerCase(), i);
});
const a = s?.login?.token;
return typeof a == "string" && t._tokens.set("login", a), e;
})), t;
}
const X = (o, t, e) => {
let s = { ...j.DEFAULT_CONFIGS };
if (typeof o == "string" ? s = E(s, {
baseURL: o,
fexiosConfigs: t || {},
defaultParams: e || {},
throwOnApiError: !1
// Set a default value for throwOnApiError
}) : typeof o == "object" && o !== null && (s = E(s, o)), !s.baseURL && typeof window == "object" && window.mediaWiki) {
const { wgServer: r, wgScriptPath: n } = window.mediaWiki?.config?.get(["wgServer", "wgScriptPath"]) || {};
typeof r == "string" && typeof n == "string" && (s.baseURL = `${r}${n}/api.php`);
}
if (typeof s.baseURL != "string")
throw new Error("baseURL is required");
return s;
}, x = () => {
}, Q = async (o, t) => {
let e = 0;
const { retry: s = 3, onRetry: r = x, shouldRetry: n = () => !0 } = t;
let a;
do
try {
return await o();
} catch (f) {
if (a = f, n(f, e))
r(f, e), e++;
else
throw f;
}
while (e < s);
throw a || new Error("Retry failed");
}, _ = class _ {
constructor(t, e, s) {
this.version = "7.6.0", this.token = this.getToken;
const r = this.config = X(
t,
e,
s
);
this.request = W(r.baseURL);
}
setBaseURL(t) {
return this.config.baseURL = t, this.request.baseConfigs.baseURL = t, this;
}
/** Base methods encapsulation */
async get(t, e) {
const s = E(
{},
this.config.fexiosConfigs,
{
query: w.mergeQueries(
this.config.defaultParams,
t
)
},
e
);
return this.runRequestWithApiErrorMapping(
() => this.request.get("", s)
);
}
async post(t, e) {
return this.runRequestWithApiErrorMapping(
() => this.request.post(
"",
t,
E(
{},
this.config.fexiosConfigs,
{
query: this.config.defaultParams
},
e
)
)
);
}
/**
* Wrap a request to map non-2xx responses containing MediaWiki API error bodies
* into MediaWikiApiError when throwOnApiError=true, and then pass 2xx responses
* through handleApiResponse for unified processing.
*/
async runRequestWithApiErrorMapping(t) {
try {
const e = await t();
return this.handleApiResponse(e);
} catch (e) {
throw this.config.throwOnApiError && y.includesMediaWikiApiError(e) ? new T(
y.extractMediaWikiApiErrors(e),
e
) : e;
}
}
throwIfApiError(t) {
const e = y.extractMediaWikiApiErrors(t);
if (e.length > 0)
throw new T(e, t);
}
handleApiResponse(t) {
return this.config.throwOnApiError && this.throwIfApiError(t.data), t;
}
/** Token Handler */
get tokens() {
return this.request._tokens;
}
async fetchTokens(t = ["csrf"]) {
return this.config.fexiosConfigs.credentials = "include", await this.get({
action: "query",
meta: "tokens",
type: t
}), this.tokens;
}
async getToken(t = "csrf", e = !1) {
return (!this.tokens.get(t) || e) && (this.tokens.delete(t), await this.fetchTokens([t])), this.tokens.get(t);
}
badToken(t) {
return this.tokens.delete(t), this.tokens;
}
async postWithToken(t, e, s) {
const {
tokenName: r = "token",
retry: n = 3,
noCache: a = !1,
fexiosOptions: f
} = s || {};
if (n < 1)
throw new y(
I.TOKEN_RETRY_LIMIT_EXCEEDED,
"The limit of the number of times to automatically re-acquire the token has been exceeded"
);
let i = 0;
return Q(
async () => {
const c = await this.getToken(
t,
a || i > 0
);
try {
const u = await this.post(
{
[r]: c,
...e
},
E(f || {}, {
customEnv: {
mwTokenName: t
}
})
);
if (y.isBadTokenError(u.data))
throw u;
return u;
} catch (u) {
throw y.isBadTokenError(u) || u?.ok === !1 || T.is(u) ? u : new y(
I.HTTP_ERROR,
"Network/transport or SDK-internal error (not a MediaWiki API error)",
u
);
}
},
{
retry: n,
onRetry: (c, u) => {
i = u + 1;
},
shouldRetry: (c) => y.isBadTokenError(c) || c?.ok === !1
}
).catch((c) => {
throw y.isBadTokenError(c) || c?.ok === !1 ? new y(
I.TOKEN_RETRY_LIMIT_EXCEEDED,
"Retry attempts for acquiring/using token exhausted",
c
) : c;
});
}
postWithEditToken(t) {
return this.postWithToken("csrf", t);
}
// for backward compatibility
/** @deprecated Use `this.config.baseURL` instead */
get baseURL() {
return this.config.baseURL;
}
/** @deprecated Use `this.config.defaultParams` instead */
get defaultParams() {
return this.config.defaultParams;
}
/** @deprecated Use `this.config.fexiosConfigs` instead */
get defaultOptions() {
return this.config.fexiosConfigs;
}
};
_.INIT_DEFAULT_PARAMS = {
action: "query",
errorformat: "plaintext",
format: "json",
formatversion: 2
}, _.DEFAULT_CONFIGS = {
baseURL: void 0,
fexiosConfigs: {
responseType: "json"
},
defaultParams: _.INIT_DEFAULT_PARAMS,
throwOnApiError: !1
}, _.createRequestHandler = W;
let j = _;
export {
G as C,
g as F,
T as M,
j as W,
y as a,
I as b,
W as c,
P as d,
z as e,
Z as f,
M as g,
K as h,
m as i,
R as j,
C as k,
J as l,
k as m,
w as n,
E as o,
N as p,
b as q,
X as r
};
//# sourceMappingURL=WikiSaikou-DPIdN41C.js.map