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~
15 lines (14 loc) • 16.6 kB
JavaScript
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var g=(i=>(i.BODY_USED="BODY_USED",i.NO_BODY_READER="NO_BODY_READER",i.TIMEOUT="TIMEOUT",i.NETWORK_ERROR="NETWORK_ERROR",i.BODY_NOT_ALLOWED="BODY_NOT_ALLOWED",i.HOOK_CONTEXT_CHANGED="HOOK_CONTEXT_CHANGED",i.ABORTED_BY_HOOK="ABORTED_BY_HOOK",i.INVALID_HOOK_CALLBACK="INVALID_HOOK_CALLBACK",i.UNEXPECTED_HOOK_RETURN="UNEXPECTED_HOOK_RETURN",i))(g||{});class y extends Error{constructor(e,o,r,s){super(o,s),this.code=e,this.context=r,this.name="FexiosError"}}class j extends y{constructor(e,o,r){super(o.statusText,e,void 0,r),this.response=o,this.name="FexiosResponseError"}}function W(i,e=1024){if(!(i instanceof Uint8Array))throw new TypeError("Input must be a Uint8Array");const o=i.slice(0,e),r=new TextDecoder("utf-8",{fatal:!0});try{const s=r.decode(o),n=/[\x00-\x08\x0E-\x1F\x7F]/g,a=s.match(n);return!(a&&a.length/s.length>.1)}catch{return!1}}function P(i){if(typeof i!="object"||i===null||Object.prototype.toString.call(i)!=="[object Object]")return!1;const e=Object.getPrototypeOf(i);return e===Object.prototype||e===null}function q(i,e={}){const o={};return Object.entries(i).forEach(([r,s])=>{s!=null&&(e.dropEmptyString&&s===""||(o[r]=s))}),o}class D{constructor(e,o,r){this.rawResponse=e,this.data=o,this.ok=e.ok,this.status=e.status,this.statusText=e.statusText,this.headers=e.headers,Object.entries(r||{}).forEach(([s,n])=>{this[s]=n})}}async function H(i,e,o){var r;if(i.bodyUsed)throw new y(g.BODY_USED,"Response body has already been used or locked");const s=i.headers.get("content-type")||"",n=Number(i.headers.get("content-length"))||0,a=(h,c)=>c==="json"||h.startsWith("application/json"),t=(h,c,u)=>u==="blob"||h.startsWith("image/")||h.startsWith("video/")||h.startsWith("audio/")||!W(c);if((i.status===101||i.status===426||i.headers.get("upgrade"))&&typeof globalThis.WebSocket<"u"){const h=new WebSocket(i.url);return await new Promise((c,u)=>{h.onopen=c,h.onerror=u}),new D(i,h,{ok:!0,status:101,statusText:"Switching Protocols"})}else if(s.startsWith("text/event-stream")&&!["text","json"].includes(e||"")&&typeof globalThis.EventSource<"u"){const h=new EventSource(i.url);return await new Promise((c,u)=>{h.onopen=c,h.onerror=u}),new D(i,h)}else{if(e==="stream")return new D(i,i.body);{const h=(r=i.clone().body)==null?void 0:r.getReader();if(!h)throw new y(g.NO_BODY_READER,"Failed to get ReadableStream from response body");let c=new Uint8Array;for(;;){const{done:l,value:b}=await h.read();if(l)break;if(b&&(c=new Uint8Array([...c,...b]),o&&n>0)){const d=Math.min(c.length/n,1);o(d,c)}}const u=new D(i,void 0);if(t(s,c,e)?u.data=new Blob([c],{type:i.headers.get("content-type")||void 0}):u.data=new TextDecoder().decode(c),a(s,e))try{u.data=JSON.parse(u.data)}catch{}if(typeof u.data=="string"&&e!=="text"){const l=u.data.trim(),b=l[0],d=l[l.length-1];if(b==="{"&&d==="}"||b==="["&&d==="]")try{u.data=JSON.parse(u.data)}catch{}}if(typeof u.data>"u"&&(u.data=c.length>0?c:void 0),u.ok)return u;throw new j(`Request failed with status code ${i.status}`,u)}}}class B{static makeSearchParams(e){const o=new URLSearchParams;return Object.entries(e).forEach(([r,s])=>{Array.isArray(s)?s.forEach(n=>o.append(r,String(n))):o.set(r,String(s))}),o}static makeQueryString(e){return this.makeSearchParams(e).toString()}}function M(i){return i&&i.__esModule&&Object.prototype.hasOwnProperty.call(i,"default")?i.default:i}var A,I;function F(){if(I)return A;I=1;function i(e){var o=this.constructor.prototype[e],r=function(){return o.apply(r,arguments)};return Object.setPrototypeOf(r,this.constructor.prototype),Object.getOwnPropertyNames(o).forEach(function(s){Object.defineProperty(r,s,Object.getOwnPropertyDescriptor(o,s))}),r}return i.prototype=Object.create(Function.prototype),A=i,A}var K=F();const $=M(K);class T extends ${constructor(e={}){super("request"),this.baseConfigs=e,this.hooks=[],this.DEFAULT_CONFIGS={baseURL:"",timeout:60*1e3,credentials:"same-origin",headers:{},query:{},responseType:void 0},this.ALL_METHODS=["get","post","put","patch","delete","head","options","trace"],this.METHODS_WITHOUT_BODY=["get","head","options","trace"],this.interceptors={request:this.createInterceptor("beforeRequest"),response:this.createInterceptor("afterResponse")},this.create=T.create,this.dropUndefinedAndNull=q,this.checkIsPlainObject=P,this.ALL_METHODS.forEach(this.createMethodShortcut.bind(this))}async request(e,o){var r,s,n,a;let t=o=o||{};typeof e=="string"||e instanceof URL?t.url=e.toString():typeof e=="object"&&(t={...e,...t}),t=await this.emit("beforeInit",t);const h=o.baseURL||this.baseConfigs.baseURL||((r=globalThis.location)==null?void 0:r.href),c=h?new URL(h,(s=globalThis.location)==null?void 0:s.href):void 0,u=new URL(t.url.toString(),c);t.url=u.href,t.baseURL=c?c.href:u.origin,t.headers=this.mergeHeaders(this.baseConfigs.headers,o.headers);const l=c==null?void 0:c.searchParams,b=new URLSearchParams(u.searchParams);if(u.search="",t.url=u.href,t.query=this.mergeQuery(l,this.baseConfigs.query,b,o.query),u.search=B.makeQueryString(t.query),t.url=u.toString(),this.METHODS_WITHOUT_BODY.includes((n=t.method)==null?void 0:n.toLocaleLowerCase())&&t.body)throw new y(g.BODY_NOT_ALLOWED,`Request method "${t.method}" does not allow body`);t=await this.emit("beforeRequest",t);let d;typeof t.body<"u"&&t.body!==null&&(t.body instanceof Blob||t.body instanceof FormData||t.body instanceof URLSearchParams?d=t.body:typeof t.body=="object"&&t.body!==null?(d=JSON.stringify(t.body),t.headers["content-type"]="application/json"):d=t.body),!((a=o.headers)!=null&&a["content-type"])&&d&&(d instanceof FormData||d instanceof URLSearchParams?delete t.headers["content-type"]:typeof d=="string"&&typeof t.body=="object"?t.headers["content-type"]="application/json":d instanceof Blob&&(t.headers["content-type"]=d.type)),t.body=d,t=await this.emit("afterBodyTransformed",t);const E=t.abortController||globalThis.AbortController?new AbortController:void 0,C=new Request(t.url,{method:t.method||"GET",credentials:t.credentials,cache:t.cache,mode:t.mode,headers:t.headers,body:t.body,signal:E==null?void 0:E.signal});t.rawRequest=C,t=await this.emit("beforeActualFetch",t);const L=t.timeout||this.baseConfigs.timeout||60*1e3;if(t.url.startsWith("ws"))try{const f=new WebSocket(t.url);return await new Promise((k,_)=>{const O=setTimeout(()=>{_(new y(g.TIMEOUT,`WebSocket connection timed out after ${L}ms`,t))},L);f.onopen=()=>{clearTimeout(O),k()},f.onerror=S=>{clearTimeout(O),_(new y(g.NETWORK_ERROR,"WebSocket connection failed",t))},f.onclose=S=>{S.code!==1e3&&(clearTimeout(O),_(new y(g.NETWORK_ERROR,`WebSocket closed with code ${S.code}`,t)))}}),t.rawResponse=new Response,t.response=new D(t.rawResponse,f,{ok:!0,status:101,statusText:"Switching Protocols"}),t.data=f,t.headers=new Headers,this.emit("afterResponse",t)}catch(f){throw f instanceof y?f:new y(g.NETWORK_ERROR,`WebSocket creation failed: ${f}`,t)}let p;try{E&&(p=setTimeout(()=>{E.abort()},L));const f=await fetch(t.rawRequest).catch(k=>{throw p&&clearTimeout(p),E!=null&&E.signal.aborted?new y(g.TIMEOUT,`Request timed out after ${L}ms`,t):new y(g.NETWORK_ERROR,k.message,t)});return p&&clearTimeout(p),t.rawResponse=f,t.response=await H(f,t.responseType,(k,_)=>{var O;(O=o==null?void 0:o.onProgress)==null||O.call(o,k,_)}),t.data=t.response.data,t.headers=t.response.headers,this.emit("afterResponse",t)}catch(f){throw p&&clearTimeout(p),f}}mergeQuery(e,...o){const r={},s=n=>{n&&(P(n)?Object.entries(n).forEach(([a,t])=>{t==null?delete r[a]:Array.isArray(t)?(a.endsWith("[]"),r[a]=t.map(String)):r[a]=String(t)}):new URLSearchParams(n).forEach((a,t)=>{r[t]=a}))};return s(e),o.forEach(s),r}mergeHeaders(e,...o){const r={},s=new Headers(e);for(const n of o)if(n!=null)if(P(n)){const a=q(n);if(Object.keys(a).length===0)continue;new Headers(a).forEach((t,h)=>{s.set(h,t)})}else new Headers(n).forEach((a,t)=>{s.set(t,a)});return s.forEach((n,a)=>{r[a]=n}),r}async emit(e,o){const r=this.hooks.filter(s=>s.event===e);try{let s=0;for(const n of r){const a=`${e}#${n.action.name||`anonymous#${s}`}`,t=Symbol("FexiosHookContext");o[t]=t;const h=await n.action.call(this,o);if(h===!1)throw new y(g.ABORTED_BY_HOOK,`Request aborted by hook "${a}"`,o);if(typeof h=="object"&&h[t]===t)o=h;else{const c=globalThis["".concat("console")];try{throw new y(g.HOOK_CONTEXT_CHANGED,`Hook "${a}" should return the original FexiosContext or return false to abort the request, but got "${h}".`)}catch(u){c.warn(u.stack||u)}}delete o[t],s++}}catch(s){return Promise.reject(s)}return o}on(e,o,r=!1){if(typeof o!="function")throw new y(g.INVALID_HOOK_CALLBACK,`Hook should be a function, but got "${typeof o}"`);return this.hooks[r?"unshift":"push"]({event:e,action:o}),this}off(e,o){return e==="*"||!e?this.hooks=this.hooks.filter(r=>r.action!==o):this.hooks=this.hooks.filter(r=>r.event!==e||r.action!==o),this}createInterceptor(e){return{handlers:()=>this.hooks.filter(o=>o.event===e).map(o=>o.action),use:(o,r=!1)=>this.on(e,o,r),clear:()=>{this.hooks=this.hooks.filter(o=>o.event!==e)}}}createMethodShortcut(e){return Object.defineProperty(this,e,{value:(o,r,s)=>(this.METHODS_WITHOUT_BODY.includes(e.toLocaleLowerCase())?s=r:(s=s||{},s.body=r),this.request(o,{...s,method:e}))}),this}extends(e){const o=new T({...this.baseConfigs,...e});return o.hooks=[...this.hooks],o}static create(e){return new T(e)}}/**
* Fexios
* @desc Fetch based HTTP client with similar API to axios for browser and Node.js
*
* @license MIT
* @author dragon-fish <dragon-fish@qq.com>
*/const Y=T.create,v=Y();typeof globalThis<"u"?globalThis.fexios=v:typeof window<"u"&&(window.fexios=v);/**
* MediaWiki Api for Axios
* Provides the API call methods similar to `mw.Api` at non-mw environments
*
* @author Dragon-Fish <dragon-fish@qq.com>
* @license MIT
*/const m=class m{constructor(e,o,r){var n,a;if(this.baseURL=e,this.version="4.2.1",this.cookies=new Map,!e&&typeof window=="object"&&window.mediaWiki){const{wgServer:t,wgScriptPath:h}=((a=(n=window.mediaWiki)==null?void 0:n.config)==null?void 0:a.get(["wgServer","wgScriptPath"]))||{};typeof t=="string"&&typeof h=="string"&&(e=`${t}${h}/api.php`)}if(typeof e!="string")throw new Error("baseURL is undefined");this.baseURL=e,this.tokens={},this.defaultParams={...m.INIT_DEFAULT_PARAMS,...r},this.defaultOptions=o||{};const s=m.createRequestHandler(this.baseURL);this.request=s,"document"in globalThis||(s.interceptors.request.use(t=>(t.headers=t.headers||{},t.headers.cookie=Array.from(this.cookies.entries()).map(([h,c])=>`${h}=${c}`).join("; "),t)),s.interceptors.response.use(t=>{const h=t.rawResponse.headers.get("set-cookie"),c=h==null?void 0:h.split(",").map(u=>u.trim());return c==null||c.forEach(u=>{const[l,...b]=u.split(";")[0].split("=");this.cookies.set(l,b.join("="))}),t}))}setBaseURL(e){return this.request.baseConfigs.baseURL=e,this}static normalizeParamValue(e){return Array.isArray(e)?e.join("|"):typeof e=="boolean"?e?"1":void 0:typeof e=="number"?""+e:e}static createRequestHandler(e){const o=new T({baseURL:e,responseType:"json"});return o.on("beforeInit",r=>{var s;if(((s=r.method)==null?void 0:s.toLowerCase())!=="post")return r;if(typeof r.body=="object"&&r.body!==null&&!(r.body instanceof URLSearchParams)&&!(r.body instanceof FormData)){const n=r.body;Object.keys(n).forEach(a=>{const t=m.normalizeParamValue(n[a]);typeof t>"u"||t===null?delete n[a]:t!==n[a]&&(n[a]=t)}),r.body=new URLSearchParams(r.body)}if(globalThis.FormData&&r.body instanceof FormData||r.body instanceof URLSearchParams){const n=r.body;n.forEach((t,h)=>{const c=m.normalizeParamValue(t);typeof c>"u"||c===null?n.delete(h):c!==t&&n.set(h,c)});const a=new URLSearchParams(r.query);!a.has("format")&&a.set("format",""+(n.get("format")||"json")),!a.has("formatversion")&&a.set("formatversion",""+(n.get("formatversion")||"2")),n.has("origin")&&a.set("origin",""+n.get("origin")),r.query=Object.fromEntries(a.entries()),n.has("action")&&(r.query.action=""+n.get("action"))}return r}),o.on("beforeInit",r=>{r.query=r.query;for(const s in r.query){const n=m.normalizeParamValue(r.query[s]);typeof n>"u"||n===null?delete r.query[s]:n!==r.query[s]&&(r.query[s]=""+n)}return r}),o.on("beforeRequest",r=>{const s=new URL(r.url),n=s.searchParams;if(globalThis.location&&(!n.has("origin")&&location.origin!==new URL(e).origin?(n.set("origin",location.origin),o.baseConfigs.credentials="include",o.baseConfigs.mode="cors"):location.origin===new URL(e).origin&&(n.delete("origin"),o.baseConfigs.credentials=void 0,o.baseConfigs.mode=void 0)),s.searchParams.has("origin")){const a=encodeURIComponent(s.searchParams.get("origin")||"").replace(/\./g,"%2E");r.query={},s.searchParams.delete("origin"),r.url=`${s}${s.search?"&":"?"}origin=${a}`}return r}),o}get(e,o){return this.request.get("",{...this.defaultOptions,query:{...this.defaultParams,...this.defaultOptions.query,...e},...o})}post(e,o){return this.request.post("",e,{...this.defaultOptions,query:{...this.defaultParams,...this.defaultOptions.query},...o})}async login(e,o,r,s){var a,t,h,c,u;if(this.defaultOptions.credentials="include",s=s||{},s.retry??(s.retry=3),s.retry<1)throw new w("LOGIN_RETRY_LIMIT_EXCEEDED","The limit of the number of times to automatically re-login has been exceeded");let n;try{const l=await this.postWithToken("login",{action:"login",lgname:e,lgpassword:o,...r},{tokenName:"lgtoken",...s});if((a=l==null?void 0:l.data)!=null&&a.login)n=l.data;else throw l}catch(l){if(l instanceof w)throw l;if((l==null?void 0:l.ok)===!1)return this.login(e,o,r,{...s,noCache:!0,retry:s.retry-1});throw new w("HTTP_ERROR","The server returns an error, but it doesn't seem to be caused by MediaWiki",l)}if(((t=n==null?void 0:n.login)==null?void 0:t.result)!=="Success")throw new w("LOGIN_FAILED",((c=(h=n==null?void 0:n.login)==null?void 0:h.reason)==null?void 0:c.text)||((u=n==null?void 0:n.login)==null?void 0:u.result)||"Login failed with unknown reason",n);return n.login}async getUserInfo(){var o;const{data:e}=await this.get({action:"query",meta:"userinfo",uiprop:["groups","rights","blockinfo"]});return(o=e==null?void 0:e.query)==null?void 0:o.userinfo}async getTokens(e=["csrf"]){this.defaultOptions.credentials="include";const{data:o}=await this.get({action:"query",meta:"tokens",type:e});return this.tokens={...this.tokens,...o.query.tokens},this.tokens}async token(e="csrf",o=!1){return(!this.tokens[`${e}token`]||o)&&(delete this.tokens[`${e}token`],await this.getTokens([e])),this.tokens[`${e}token`]}async postWithToken(e,o,r){const{tokenName:s="token",retry:n=3,noCache:a=!1}=r||{};if(n<1)throw new w("TOKEN_RETRY_LIMIT_EXCEEDED","The limit of the number of times to automatically re-acquire the token has been exceeded");const t=await this.token(e,a),h=()=>this.postWithToken(e,o,{tokenName:s,retry:n-1,noCache:!0});return this.post({[s]:t,...o}).then(c=>{const u=c.data;return m.isBadTokenError(u)?h():c}).catch(c=>{const u=c.data;if(m.isBadTokenError(u)||(c==null?void 0:c.ok)===!1)return h();if(typeof u=="object"&&u!==null)return Promise.reject(u);throw new w("HTTP_ERROR","The server returns an error, but it doesn’t seem to be caused by MediaWiki",c)})}postWithEditToken(e){return this.postWithToken("csrf",e)}static isBadTokenError(e){var o,r,s;return((o=e==null?void 0:e.error)==null?void 0:o.code)==="badtoken"||((r=e==null?void 0:e.errors)==null?void 0:r.some(n=>n.code==="badtoken"))||["NeedToken","WrongToken"].includes((s=e==null?void 0:e.login)==null?void 0:s.result)}async getMessages(e,o="zh",r){const{data:s}=await this.get({action:"query",meta:"allmessages",ammessages:e,amlang:o,...r}),n={};return s.query.allmessages.forEach(function(a){a.missing||(n[a.name]=a.content)}),n}async parseWikitext(e,o,r,s){const{data:n}=await this.post({action:"parse",title:o,text:e,...r},s);return n.parse.text}};m.INIT_DEFAULT_PARAMS={action:"query",errorformat:"plaintext",format:"json",formatversion:2};let R=m;class N extends R{constructor(e,o,r){super(e,{credentials:"include",mode:"cors",...o},{origin:location.origin,...r})}}var U=(i=>(i.HTTP_ERROR="HTTP_ERROR",i.LOGIN_FAILED="LOGIN_FAILED",i.LOGIN_RETRY_LIMIT_EXCEEDED="LOGIN_RETRY_LIMIT_EXCEEDED",i.TOKEN_RETRY_LIMIT_EXCEEDED="TOKEN_RETRY_LIMIT_EXCEEDED",i))(U||{});class w extends Error{constructor(e,o="",r){super(),this.code=e,this.message=o,this.cause=r,this.name="WikiSaikouError"}}exports.ForeignApi=N;exports.MediaWikiApi=R;exports.MediaWikiForeignApi=N;exports.MwApi=R;exports.WikiSaikouError=w;exports.WikiSaikouErrorCode=U;exports.default=R;
//# sourceMappingURL=index.cjs.map