From 179c46aefbadf6130579f64080fa41b6b45593d7 Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 09:02:02 +0800 Subject: [PATCH 01/12] refactor: replace lyla with fexios --- package.json | 4 +- pnpm-lock.yaml | 16 +- src/index.ts | 184 ++++++-------------- src/modules/lyla-adapter-fetch/adapter.ts | 101 ----------- src/modules/lyla-adapter-fetch/index.ts | 13 -- src/modules/lyla-adapter-fetch/instance.ts | 17 -- src/modules/lyla-adapter-fetch/reexports.ts | 37 ---- test/1.core.spec.ts | 6 +- 8 files changed, 69 insertions(+), 309 deletions(-) delete mode 100644 src/modules/lyla-adapter-fetch/adapter.ts delete mode 100644 src/modules/lyla-adapter-fetch/index.ts delete mode 100644 src/modules/lyla-adapter-fetch/instance.ts delete mode 100644 src/modules/lyla-adapter-fetch/reexports.ts diff --git a/package.json b/package.json index 1be8f51..6eb0835 100644 --- a/package.json +++ b/package.json @@ -41,8 +41,8 @@ }, "homepage": "https://github.com/moegirlwiki/wiki-saikou#readme", "dependencies": { - "@lylajs/core": "^1.2.0", - "@vue/reactivity": "^3.3.4" + "@vue/reactivity": "^3.3.4", + "fexios": "^1.1.0" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2741f97..b3c12f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,16 +1,16 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true excludeLinksFromLockfile: false dependencies: - '@lylajs/core': - specifier: ^1.2.0 - version: 1.2.0 '@vue/reactivity': specifier: ^3.3.4 version: 3.3.4 + fexios: + specifier: ^1.1.0 + version: 1.1.0 devDependencies: '@types/chai': @@ -523,10 +523,6 @@ packages: wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true - /@lylajs/core@1.2.0: - resolution: {integrity: sha512-JFkOzbi3i6g2Ho4Ec9AknOuL8lyr8jinQh3XPuv8QSJ0PIJG1wGMDgKPUEOeXJbKY5tKu7Y97+dP7oidpAehvw==} - dev: false - /@microsoft/api-extractor-model@7.27.4(@types/node@18.16.19): resolution: {integrity: sha512-HjqQFmuGPOS20rtnu+9Jj0QrqZyR59E+piUWXPMZTTn4jaZI+4UmsHSf3Id8vyueAhOBH2cgwBuRTE5R+MfSMw==} dependencies: @@ -1162,6 +1158,10 @@ packages: reusify: 1.0.4 dev: true + /fexios@1.1.0: + resolution: {integrity: sha512-Bf5Jmyfzx7C7r2DkBADotOWbvSxNjjFtmF0rgdT8P5T+751s9WltbP2o6vKR5ffoTiQfXZaDctikjlyQVT/ebw==} + dev: false + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} diff --git a/src/index.ts b/src/index.ts index 88d2d61..7070bf1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,26 +8,21 @@ import { Ref, ref, computed, ComputedRef } from '@vue/reactivity' import { - LylaAdapterMeta, - createLyla, - LylaRequestOptions, - LylaResponse, -} from './modules/lyla-adapter-fetch' -import { Lyla } from '@lylajs/core' - -type LylaResponseWith = LylaResponse & { - data: T -} + Fexios, + FexiosConfigs, + FexiosRequestOptions, + FexiosResponse, +} from 'fexios' export class MediaWikiApi { baseURL: Ref - #requestHandler: ComputedRef> - #defaultOptions: Ref + #requestHandler: ComputedRef + #defaultOptions: Ref> #defaultParams: Ref #tokens: Record cookies: Record = {} - constructor(baseURL?: string, options?: LylaRequestOptions) { + constructor(baseURL?: string, options?: Partial) { // For MediaWiki environment if (!baseURL && typeof window === 'object' && (window as any).mediaWiki) { const scriptPath: string | undefined = ( @@ -42,7 +37,7 @@ export class MediaWikiApi { this.baseURL = ref(baseURL) this.#tokens = {} this.#defaultParams = ref({}) - this.#defaultOptions = ref({}) + this.#defaultOptions = ref({} as any) // Set default values this.defaultParams = { @@ -54,48 +49,21 @@ export class MediaWikiApi { this.defaultOptions = options || {} this.#requestHandler = computed(() => { - const options: LylaRequestOptions = { - ...this.#defaultOptions.value, - } - - options.hooks ??= {} - options.hooks.onInit ??= [] - options.hooks.onBeforeRequest ??= [] - options.hooks.onAfterResponse ??= [] - - // Inject default query params - options.hooks.onInit?.unshift((ctx) => { - // @ts-ignore FIXME: Type error during vite build, too bad! - ctx.query = { - ...this.#defaultParams.value, - ...ctx.query, - } - - // Fix baseURL - !ctx.url && (ctx.url = this.baseURL.value) - try { - ctx.url = new URL( - ctx.url, - this.baseURL.value.startsWith('http') - ? this.baseURL.value - : globalThis.location?.href - ).toString() - } catch (_) {} - - return ctx + const instance = MediaWikiApi.createRequestHandler(this.baseURL.value, { + ...this.defaultOptions, + query: this.defaultParams as any, }) - // Handle cookies for Node.js if (!('document' in globalThis)) { - options.hooks.onBeforeRequest.push((ctx) => { - ctx.headers = ctx.headers || {} + instance.interceptors.request.use((ctx) => { + ctx.headers = (ctx.headers as Record) || {} ctx.headers['cookie'] = Object.keys(this.cookies) .map((name) => `${name}=${this.cookies[name]}`) .join(';') return ctx }) - options.hooks.onAfterResponse.push((ctx) => { - const cookieHeaders = (ctx.detail.headers as Headers).get( + instance.interceptors.response.use((ctx) => { + const cookieHeaders = (ctx.rawResponse!.headers as Headers).get( 'set-cookie' ) const rawCookies = cookieHeaders?.split(',').map((i) => i.trim()) @@ -107,7 +75,7 @@ export class MediaWikiApi { }) } - return MediaWikiApi.createLylaInstance(this.baseURL.value, options) + return instance }) } @@ -122,38 +90,19 @@ export class MediaWikiApi { return item } } - static createLylaInstance(baseURL: string, options: LylaRequestOptions = {}) { - options.hooks ??= {} - options.hooks.onInit ??= [] - options.hooks.onBeforeRequest ??= [] - options.hooks.onAfterResponse ??= [] - options.hooks.onResponseError ??= [] - - options.hooks.onInit.push((ctx) => { - // console.info( - // '[onInit] beforeTransform', - // ctx.method, - // ctx.url, - // ctx.query, - // ctx.body - // ) - + static createRequestHandler( + baseURL: string, + options: Partial = {} + ) { + const instance = new Fexios(options) + instance.baseConfigs.baseURL = baseURL + + // Adjust body + instance.on('beforeInit', (ctx) => { if (ctx.method?.toLowerCase() !== 'post') { return ctx } - // Transform json to formdata - if (ctx.json) { - const form = new URLSearchParams('') - for (const key in ctx.json) { - const data = MediaWikiApi.normalizeParamValue(ctx.json[key]) - if (typeof data === 'undefined') continue - form.append(key, '' + data) - } - ctx.body = form - ctx.json = undefined - } - if ( (globalThis.FormData && ctx.body instanceof FormData) || ctx.body instanceof URLSearchParams @@ -169,18 +118,25 @@ export class MediaWikiApi { } }) // Adjust query - ctx.query ??= {} - ctx.query.format ??= '' + body.get('format') || 'json' - ctx.query.formatversion ??= '' + body.get('formatversion') || '2' - body.has('origin') && (ctx.query.origin = '' + body.get('origin')) + const searchParams = new URLSearchParams(ctx.query as any) + !searchParams.has('format') && + searchParams.set('format', '' + body.get('format') || 'json') + !searchParams.has('formatversion') && + searchParams.set( + 'formatversion', + '' + body.get('formatversion') || '2' + ) + body.has('origin') && + searchParams.set('origin', '' + body.get('origin')) + ctx.query = searchParams } return ctx }) // Adjust query - options.hooks.onInit.push((ctx) => { - ctx.query ??= {} + instance.on('beforeRequest', (ctx) => { + ctx.query = ctx.query as Record for (const key in ctx.query) { const data = MediaWikiApi.normalizeParamValue(ctx.query[key]) if (typeof data === 'undefined' || data === null) { @@ -189,52 +145,24 @@ export class MediaWikiApi { ctx.query[key] = '' + data } } - - // console.info('[onInit]', ctx.method?.toUpperCase(), ctx.url, { - // query: ctx.query, - // body: ctx.body, - // headers: ctx.headers, - // }) return ctx }) // Adjust origin param - options.hooks.onBeforeRequest.push((ctx) => { + instance.on('beforeRequest', (ctx) => { const url = new URL(ctx.url!) if (url.searchParams.has('origin')) { const origin = encodeURIComponent( url.searchParams.get('origin') || '' ).replace(/\./g, '%2E') - delete ctx.query + ctx.query = {} url.searchParams.delete('origin') ctx.url = `${url}${url.search ? '&' : '?'}origin=${origin}` } return ctx }) - /** - * response.data shortcut compatibility - */ - options.hooks.onAfterResponse.push((ctx) => { - Object.defineProperty(ctx, 'data', { - get() { - try { - return JSON.parse(ctx.body as string) - } catch (_) { - return ctx.body - } - }, - }) - return ctx - }) - - // @ts-ignore FIXME: Type error during vite build, too bad! - const { lyla } = createLyla({ - baseUrl: baseURL, - ...options, - }) - - return lyla + return instance } /** Syntactic Sugar */ @@ -246,7 +174,7 @@ export class MediaWikiApi { get defaultOptions() { return this.#defaultOptions.value } - set defaultOptions(options: LylaRequestOptions) { + set defaultOptions(options: Partial) { this.#defaultOptions.value = options } // defaultParams @@ -258,17 +186,17 @@ export class MediaWikiApi { } /** Base methods encapsulation */ - get(query: MwApiParams, options?: LylaRequestOptions) { - return this.request.get(this.baseURL.value, { + get(query: MwApiParams, options?: FexiosRequestOptions) { + return this.request.get('', { query: query as any, ...options, - }) as Promise> + }) } - post(data: MwApiParams, options?: LylaRequestOptions) { - return this.request.post(this.baseURL.value, { - json: data, + post(data: MwApiParams, options?: FexiosRequestOptions) { + return this.request.post('', { + data, ...options, - }) as Promise> + }) } async login( @@ -285,7 +213,7 @@ export class MediaWikiApi { lguserid: number lgusername: string }> { - this.defaultOptions.withCredentials = true + this.defaultOptions.credentials = 'include' const { data } = await this.postWithToken( 'login', { @@ -329,7 +257,7 @@ export class MediaWikiApi { /** Token Handler */ async getTokens(type: MwTokenName[] = ['csrf']) { - this.defaultOptions.withCredentials = true + this.defaultOptions.credentials = 'include' const { data } = await this.get({ action: 'query', meta: 'tokens', @@ -350,7 +278,7 @@ export class MediaWikiApi { tokenType: MwTokenName, body: MwApiParams, options?: { tokenName?: string; retry?: number; noCache?: boolean } - ): Promise> { + ): Promise> { const { tokenName = 'token', retry = 3, noCache = false } = options || {} if (retry < 1) { return Promise.reject({ @@ -407,7 +335,7 @@ export class MediaWikiApi { wikitext: string, title?: string, extraBody?: MwApiParams, - options?: LylaRequestOptions + options?: FexiosRequestOptions ): Promise { const { data } = await this.post( { @@ -423,9 +351,9 @@ export class MediaWikiApi { } export class MediaWikiForeignApi extends MediaWikiApi { - constructor(baseURL?: string, options?: LylaRequestOptions) { + constructor(baseURL?: string, options?: FexiosRequestOptions) { super(baseURL, { - withCredentials: true, + credentials: 'include', ...options, }) this.defaultParams.origin = location.origin diff --git a/src/modules/lyla-adapter-fetch/adapter.ts b/src/modules/lyla-adapter-fetch/adapter.ts deleted file mode 100644 index e48fc45..0000000 --- a/src/modules/lyla-adapter-fetch/adapter.ts +++ /dev/null @@ -1,101 +0,0 @@ -import type { - LylaAdapter, - LylaAdapterMeta as LylaCoreAdapterMeta, -} from '@lylajs/core' - -export interface LylaAdapterMeta extends LylaCoreAdapterMeta { - method: - | 'get' - | 'GET' - | 'post' - | 'POST' - | 'put' - | 'PUT' - | 'patch' - | 'PATCH' - | 'head' - | 'HEAD' - | 'delete' - | 'DELETE' - | 'options' - | 'OPTIONS' - | 'connect' - | 'CONNECT' - | 'trace' - | 'TRACE' - networkErrorDetail: TypeError - requestBody: string | FormData - responseDetail: Response - responseType: 'arraybuffer' | 'blob' | 'text' - body: BodyInit -} - -function transformHeaders(headers: Headers): Record { - if (!headers) return {} - - const headerMap: Record = {} - headers.forEach((value, key) => { - headerMap[key] = value - }) - - return headerMap -} - -export const adapter: LylaAdapter = ({ - url, - method, - headers, - body, - responseType, - withCredentials, - onDownloadProgress, - onUploadProgress, - onResponse, - onNetworkError, -}): { - abort: () => void -} => { - const abortController = new AbortController() - const request = fetch(url, { - method, - headers, - body, - credentials: withCredentials ? 'include' : 'same-origin', - signal: abortController.signal, - }) - - request.then(async (response) => { - let body: any - if (responseType === 'blob') { - try { - body = await response.clone().blob() - } catch (error) {} - } else if (responseType === 'arraybuffer') { - try { - body = await response.clone().arrayBuffer() - } catch (error) {} - } - if (!body) { - body = await response.clone().text() - } - - onResponse( - { - status: response.status, - headers: transformHeaders(response.headers), - body, - }, - response - ) - }) - - request.catch((error) => { - onNetworkError(error) - }) - - return { - abort() { - abortController.abort() - }, - } -} diff --git a/src/modules/lyla-adapter-fetch/index.ts b/src/modules/lyla-adapter-fetch/index.ts deleted file mode 100644 index b6ca3a3..0000000 --- a/src/modules/lyla-adapter-fetch/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export { adapter } from './adapter' -export type { LylaAdapterMeta } from './adapter' -export { lyla, isLylaError, createLyla } from './instance' -export type { - Lyla, - LylaError, - LylaProgress, - LylaRequestOptions, - LylaResponse, - LylaResponseError, - LylaDataConversionError, -} from './reexports' -export { LYLA_ERROR, LylaAbortController } from './reexports' diff --git a/src/modules/lyla-adapter-fetch/instance.ts b/src/modules/lyla-adapter-fetch/instance.ts deleted file mode 100644 index ab56e40..0000000 --- a/src/modules/lyla-adapter-fetch/instance.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createLyla as coreCreateLyla } from '@lylajs/core' -import { adapter } from './adapter' -import type { - LylaRequestOptions, - LylaRequestOptionsWithContext, -} from './reexports' - -export const { lyla, isLylaError } = coreCreateLyla(adapter, { - context: undefined, -}) - -export const createLyla = ( - options: LylaRequestOptionsWithContext, - ...overrides: LylaRequestOptions[] -) => { - return coreCreateLyla(adapter, options, ...overrides) -} diff --git a/src/modules/lyla-adapter-fetch/reexports.ts b/src/modules/lyla-adapter-fetch/reexports.ts deleted file mode 100644 index ba7b33a..0000000 --- a/src/modules/lyla-adapter-fetch/reexports.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { - LylaRequestOptions as LylaCoreRequestOptions, - LylaResponse as LylaCoreResponse, - Lyla as LylaCore, - LylaRequestOptionsWithContext as LylaCoreRequestOptionsWithContext, -} from '@lylajs/core' -import type { - LylaResponseError as LylaCoreResponseError, - LylaError as LylaCoreError, - LylaDataConversionError as LylaCoreDataConversionError, -} from '@lylajs/core' -import type { LylaAdapterMeta } from './adapter' - -// core -export type Lyla = LylaCore -export type LylaRequestOptions = LylaCoreRequestOptions< - C, - LylaAdapterMeta -> -export type LylaRequestOptionsWithContext = - LylaCoreRequestOptionsWithContext -export type LylaResponse = LylaCoreResponse< - T, - C, - LylaAdapterMeta -> - -// error -export type LylaResponseError = LylaCoreResponseError< - C, - LylaAdapterMeta -> -export type LylaDataConversionError = - LylaCoreDataConversionError -export type LylaError = LylaCoreError - -export { LYLA_ERROR, LylaProgress, LylaAbortController } from '@lylajs/core' diff --git a/test/1.core.spec.ts b/test/1.core.spec.ts index 3e70434..fbf448a 100644 --- a/test/1.core.spec.ts +++ b/test/1.core.spec.ts @@ -69,13 +69,13 @@ describe('MediaWikiApi', () => { // timeout: 114514, // } - // expect(api.ajax.defaults.baseURL).to.equal( + // expect(api.request.baseConfigs.baseURL).to.equal( // 'https://commons.moegirl.org.cn/api.php' // ) - // expect(api.ajax.defaults.params).to.deep.equal({ + // expect(api.request.baseConfigs.query).to.deep.equal({ // key1: 'value1', // key2: 'value2', // }) - // expect(api.ajax.defaults.timeout).to.equal(114514) + // expect(api.request.baseConfigs.timeout).to.equal(114514) // }) }) From 419ba3d74c9b4912c12a03426872fecc17af52aa Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 09:57:04 +0800 Subject: [PATCH 02/12] fix: params normalized --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- src/index.ts | 38 +++++++++++++++++++++++++++++--------- test/2.foreign.spec.ts | 18 ++++++++++++------ 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 6eb0835..9771473 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "homepage": "https://github.com/moegirlwiki/wiki-saikou#readme", "dependencies": { "@vue/reactivity": "^3.3.4", - "fexios": "^1.1.0" + "fexios": "^1.1.1" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3c12f4..a8d5734 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ dependencies: specifier: ^3.3.4 version: 3.3.4 fexios: - specifier: ^1.1.0 - version: 1.1.0 + specifier: ^1.1.1 + version: 1.1.1 devDependencies: '@types/chai': @@ -1158,8 +1158,8 @@ packages: reusify: 1.0.4 dev: true - /fexios@1.1.0: - resolution: {integrity: sha512-Bf5Jmyfzx7C7r2DkBADotOWbvSxNjjFtmF0rgdT8P5T+751s9WltbP2o6vKR5ffoTiQfXZaDctikjlyQVT/ebw==} + /fexios@1.1.1: + resolution: {integrity: sha512-PccqJ+hUKo4y48cgLcKTd4jqerkqipCnyDJgDMHH+O4l4EBlxUJ18Ze8Miyy9CpAT0H3ISVOwinMd9vz/saS2Q==} dev: false /fill-range@7.0.1: diff --git a/src/index.ts b/src/index.ts index 7070bf1..d5ec36f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -103,6 +103,24 @@ export class MediaWikiApi { return ctx } + if ( + typeof ctx.body === 'object' && + ctx.body !== null && + !(ctx.body instanceof URLSearchParams) && + !(ctx.body instanceof FormData) + ) { + const body: any = ctx.body + Object.keys(body).forEach((key) => { + const data = MediaWikiApi.normalizeParamValue(body[key]) + if (typeof data === 'undefined' || data === null) { + delete body[key] + } else if (data !== body[key]) { + body[key] = data + } + }) + ctx.body = new URLSearchParams(ctx.body as any) + } + if ( (globalThis.FormData && ctx.body instanceof FormData) || ctx.body instanceof URLSearchParams @@ -120,22 +138,22 @@ export class MediaWikiApi { // Adjust query const searchParams = new URLSearchParams(ctx.query as any) !searchParams.has('format') && - searchParams.set('format', '' + body.get('format') || 'json') + searchParams.set('format', '' + (body.get('format') || 'json')) !searchParams.has('formatversion') && searchParams.set( 'formatversion', - '' + body.get('formatversion') || '2' + '' + (body.get('formatversion') || '2') ) body.has('origin') && searchParams.set('origin', '' + body.get('origin')) - ctx.query = searchParams + ctx.query = Object.fromEntries(searchParams) } return ctx }) // Adjust query - instance.on('beforeRequest', (ctx) => { + instance.on('beforeInit', (ctx) => { ctx.query = ctx.query as Record for (const key in ctx.query) { const data = MediaWikiApi.normalizeParamValue(ctx.query[key]) @@ -150,6 +168,8 @@ export class MediaWikiApi { // Adjust origin param instance.on('beforeRequest', (ctx) => { + const rawRequest = ctx.rawRequest! + const url = new URL(ctx.url!) if (url.searchParams.has('origin')) { const origin = encodeURIComponent( @@ -159,6 +179,9 @@ export class MediaWikiApi { url.searchParams.delete('origin') ctx.url = `${url}${url.search ? '&' : '?'}origin=${origin}` } + + ctx.rawRequest = new Request(ctx.url, rawRequest) + return ctx }) @@ -193,10 +216,7 @@ export class MediaWikiApi { }) } post(data: MwApiParams, options?: FexiosRequestOptions) { - return this.request.post('', { - data, - ...options, - }) + return this.request.post('', data, options) } async login( @@ -351,7 +371,7 @@ export class MediaWikiApi { } export class MediaWikiForeignApi extends MediaWikiApi { - constructor(baseURL?: string, options?: FexiosRequestOptions) { + constructor(baseURL?: string, options?: Partial) { super(baseURL, { credentials: 'include', ...options, diff --git a/test/2.foreign.spec.ts b/test/2.foreign.spec.ts index df26c64..6422bac 100644 --- a/test/2.foreign.spec.ts +++ b/test/2.foreign.spec.ts @@ -14,7 +14,7 @@ const api = new MediaWikiForeignApi('https://commons.moegirl.org.cn/api.php', { describe('MediaWikiForeignApi', () => { it('[GET] siteinfo', async () => { - const { data, headers } = await api + const { data, response } = await api .get({ action: 'query', meta: 'siteinfo', @@ -23,22 +23,26 @@ describe('MediaWikiForeignApi', () => { console.warn(e) return Promise.reject(e) }) - expect(headers['access-control-allow-origin']).to.equal(location.origin) + expect(response.headers.get('access-control-allow-origin')).to.equal( + location.origin + ) expect(data.query.general.sitename).to.equal('萌娘共享') }) it('[GET] array as param', async () => { - const { data, headers } = await api.get({ + const { data, response } = await api.get({ action: 'query', meta: ['siteinfo', 'userinfo'], }) - expect(headers['access-control-allow-origin']).to.equal(location.origin) + expect(response.headers.get('access-control-allow-origin')).to.equal( + location.origin + ) expect(data.query.general).to.not.be.undefined expect(data.query.userinfo).to.not.be.undefined }) it('[POST] parse', async () => { - const { data, headers } = await api + const { data, response } = await api .post({ action: 'parse', title: 'Custom Page', @@ -51,7 +55,9 @@ describe('MediaWikiForeignApi', () => { return Promise.reject(e) }) // console.info({ data, headers }) - expect(headers['access-control-allow-origin']).to.equal(location.origin) + expect(response.headers.get('access-control-allow-origin')).to.equal( + location.origin + ) expect(data.parse.title).to.eq('Custom Page') expect(data.parse.text).to.includes('bold') expect(data.parse.text).to.includes('italic') From 79f1f936f5de6975119447fc73a6a0a3814d8fc7 Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 10:03:22 +0800 Subject: [PATCH 03/12] chore: upgrade deps --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- src/index.ts | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 9771473..d406b3b 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "homepage": "https://github.com/moegirlwiki/wiki-saikou#readme", "dependencies": { "@vue/reactivity": "^3.3.4", - "fexios": "^1.1.1" + "fexios": "^1.2.0" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8d5734..effaf29 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ dependencies: specifier: ^3.3.4 version: 3.3.4 fexios: - specifier: ^1.1.1 - version: 1.1.1 + specifier: ^1.2.0 + version: 1.2.0 devDependencies: '@types/chai': @@ -1158,8 +1158,8 @@ packages: reusify: 1.0.4 dev: true - /fexios@1.1.1: - resolution: {integrity: sha512-PccqJ+hUKo4y48cgLcKTd4jqerkqipCnyDJgDMHH+O4l4EBlxUJ18Ze8Miyy9CpAT0H3ISVOwinMd9vz/saS2Q==} + /fexios@1.2.0: + resolution: {integrity: sha512-UTXmXvYT/tAVR+Ox3WrdWxJTuriGsh1yPR1/XldM6UFyMMED9pYiDodZydZ1k3rjyoAwd3FDYlcFp0Oiq/h2Xg==} dev: false /fill-range@7.0.1: diff --git a/src/index.ts b/src/index.ts index d5ec36f..a07d17c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -168,8 +168,6 @@ export class MediaWikiApi { // Adjust origin param instance.on('beforeRequest', (ctx) => { - const rawRequest = ctx.rawRequest! - const url = new URL(ctx.url!) if (url.searchParams.has('origin')) { const origin = encodeURIComponent( @@ -179,9 +177,6 @@ export class MediaWikiApi { url.searchParams.delete('origin') ctx.url = `${url}${url.search ? '&' : '?'}origin=${origin}` } - - ctx.rawRequest = new Request(ctx.url, rawRequest) - return ctx }) From 9f9cd71dc256d7ae6f434cea03579cb99b4482bb Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 10:12:55 +0800 Subject: [PATCH 04/12] chore: minor fixes, bump version (3.0.0-rc.0) --- package.json | 2 +- src/index.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index d406b3b..d41302a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wiki-saikou", - "version": "2.0.0", + "version": "3.0.0-rc.0", "description": "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~", "main": "./lib/index.js", "types": "./lib/index.d.ts", diff --git a/src/index.ts b/src/index.ts index a07d17c..bb4a4a8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ import { Fexios, FexiosConfigs, FexiosRequestOptions, - FexiosResponse, + FexiosFinalContext, } from 'fexios' export class MediaWikiApi { @@ -293,7 +293,7 @@ export class MediaWikiApi { tokenType: MwTokenName, body: MwApiParams, options?: { tokenName?: string; retry?: number; noCache?: boolean } - ): Promise> { + ): Promise> { const { tokenName = 'token', retry = 3, noCache = false } = options || {} if (retry < 1) { return Promise.reject({ From 7b1b40fe2f63b22f0725bf6a659aae6093852261 Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 19:38:41 +0800 Subject: [PATCH 05/12] fix: token clean up --- src/index.ts | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index bb4a4a8..29636f0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -307,19 +307,23 @@ export class MediaWikiApi { return this.post({ [tokenName]: token, ...body, - }).catch(({ data }) => { - if ( - [data?.errors?.[0].code, data?.error?.code].includes('badtoken') || - ['NeedToken', 'WrongToken'].includes(data?.login?.result) - ) { - return this.postWithToken(tokenType, data, { - tokenName, - retry: retry - 1, - noCache: true, - }) - } - return Promise.reject(data) }) + .catch(({ data }) => { + if ( + [data?.errors?.[0].code, data?.error?.code].includes('badtoken') || + ['NeedToken', 'WrongToken'].includes(data?.login?.result) + ) { + return this.postWithToken(tokenType, data, { + tokenName, + retry: retry - 1, + noCache: true, + }) + } + return Promise.reject(data) + }) + .finally(() => { + delete this.#tokens[`${tokenType}token`] + }) } postWithEditToken(body: MwApiParams) { return this.postWithToken('csrf', body) From 2b23c1e008f22a88ca1259610e17f2106972151b Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 19:39:07 +0800 Subject: [PATCH 06/12] chore: bump version (3.0.0-rc.1) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d41302a..df82cf0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wiki-saikou", - "version": "3.0.0-rc.0", + "version": "3.0.0-rc.1", "description": "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~", "main": "./lib/index.js", "types": "./lib/index.d.ts", From d6ae49bde15327e7c1c8f13b0c85c4ddba6c98c7 Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 19:44:36 +0800 Subject: [PATCH 07/12] fix: type adjustments --- src/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 29636f0..031f06a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -210,7 +210,10 @@ export class MediaWikiApi { ...options, }) } - post(data: MwApiParams, options?: FexiosRequestOptions) { + post( + data: MwApiParams | URLSearchParams | FormData, + options?: FexiosRequestOptions + ) { return this.request.post('', data, options) } @@ -257,9 +260,9 @@ export class MediaWikiApi { blockid?: number blockedby?: string blockedbyid?: number - blockedtimestamp?: string blockreason?: string blockexpiry?: string + blockedtimestamp?: string } } }>({ From 8818d0441732ff5968c381e4fd0303e4110035b5 Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 20:15:51 +0800 Subject: [PATCH 08/12] doc: update README --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f5a5c41..71825e6 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Below is the documentation of MediaWikiApi. **Main methods**: -#### `new MediaWikiApi(baseURL?: string, options?: LylaRequestOptions)` +#### `new MediaWikiApi(baseURL?: string, options?: Partial)` - `baseURL`: API endpoint of your target wiki site (e.g. https://mediawiki.org/w/api.php) - **Not required but with conditions**: If you are using it in the browser environment, and the website runs MediaWiki. The instance will automatically use the API endpoint of current wiki. @@ -75,15 +75,15 @@ Below is the documentation of MediaWikiApi. Login your account. -#### `get(params: MwApiParams, options?: LylaRequestOptions): Promise>` +#### `get(params: MwApiParams, options?: FexiosRequestOptions): Promise>` Make `GET` request -#### `post(body: MwApiParams, options?: LylaRequestOptions): Promise>` +#### `post(body: MwApiParams, options?: LylaRequestOptions): Promise>` Make `POST` request -#### `postWithToken(tokenType: MwTokenName, body: MwApiParams, options?: LylaRequestOptions): Promise>` +#### `postWithToken(tokenType: MwTokenName, body: MwApiParams, options?: LylaRequestOptions): Promise>` Make `POST` request with specified token. @@ -111,9 +111,9 @@ Normalize input params to standard MediaWiki request params. - `string[] → string`: `['foo', 'bar', 'baz'] → 'foo|bar|baz` - `false → undefined`: remove false items -#### `MediaWikiApi.createLylaInstance(baseURL: string, options?: LylaRequestOptions): Lyla` (static) +#### `MediaWikiApi.createRequestHandler(baseURL: string, options?: Partial): Fexios` (static) -Create your own Lyla instance. +Create your own Fexios instance. **Warning: The instance created by this method does not include responsive getters/setters (described below) and the out of box cookie controls.** From 3df307e2b8afc49f310ca5cb60fc1cbfd0661881 Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 21:14:50 +0800 Subject: [PATCH 09/12] build: install tslib as dependency --- package.json | 4 ++-- pnpm-lock.yaml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index df82cf0..089102b 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "homepage": "https://github.com/moegirlwiki/wiki-saikou#readme", "dependencies": { "@vue/reactivity": "^3.3.4", - "fexios": "^1.2.0" + "fexios": "^1.2.0", + "tslib": "^2.6.0" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -56,7 +57,6 @@ "mocha": "^10.2.0", "rimraf": "^5.0.1", "ts-mocha": "^10.0.0", - "tslib": "^2.6.0", "tsup": "^7.1.0", "tsx": "^3.12.7", "typescript": "^5.1.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index effaf29..d4f669d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ dependencies: fexios: specifier: ^1.2.0 version: 1.2.0 + tslib: + specifier: ^2.6.0 + version: 2.6.0 devDependencies: '@types/chai': @@ -46,9 +49,6 @@ devDependencies: ts-mocha: specifier: ^10.0.0 version: 10.0.0(mocha@10.2.0) - tslib: - specifier: ^2.6.0 - version: 2.6.0 tsup: specifier: ^7.1.0 version: 7.1.0(typescript@5.1.6) @@ -2059,7 +2059,7 @@ packages: /tslib@2.6.0: resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} - dev: true + dev: false /tsup@7.1.0(typescript@5.1.6): resolution: {integrity: sha512-mazl/GRAk70j8S43/AbSYXGgvRP54oQeX8Un4iZxzATHt0roW0t6HYDVZIXMw0ZQIpvr1nFMniIVnN5186lW7w==} From fbf1e5aebfefb90b4c18ed2e78ee6b15dbe8f1e9 Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 22:21:42 +0800 Subject: [PATCH 10/12] build: drop console --- vite.config.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vite.config.ts b/vite.config.ts index 56bf05c..104d7d9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,6 +2,10 @@ import { resolve } from 'path' import { defineConfig } from 'vite' import dts from 'vite-plugin-dts' +const PROD = + process.env.NODE_ENV === 'production' && + process.env.BUILD_ENV !== 'development' + export default defineConfig({ build: { lib: { @@ -12,7 +16,9 @@ export default defineConfig({ }, sourcemap: true, }, - esbuild: {}, + esbuild: { + drop: PROD ? ['console'] : [], + }, define: { // @FIX Uncaught ReferenceError: process is not defined // @link https://github.com/vitejs/vite/issues/9186 From cd1986c37a545066cd5c48ea999370889e97f2e8 Mon Sep 17 00:00:00 2001 From: Dragon-Fish Date: Sun, 16 Jul 2023 22:23:50 +0800 Subject: [PATCH 11/12] doc: update README --- README.md | 14 +++++++------- package.json | 4 +++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 71825e6..2312660 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ The library provides the out of box accessing to MediaWiki API in both browsers - With unit tests - User authentication supports out of the box \*(also applicable to Node.js!) -## 开箱即用/Out of box +## 开箱即用 Out of box -**安装/installation** +**安装 Installation** ```sh # Via pnpm: @@ -42,7 +42,7 @@ const api = new MediaWikiApi('https://zh.moegirl.org.cn/api.php') // ... ``` -**在浏览器中直接使用/Use directly in the browser** +**在浏览器中直接使用 Use directly in the browser** ```js import('https://unpkg.com/wiki-saikou?module').then(({ MediaWikiApi }) => { @@ -53,7 +53,7 @@ import('https://unpkg.com/wiki-saikou?module').then(({ MediaWikiApi }) => { Then use it just like the `new mw.Api()` -## 使用方法/Usage +## 使用方法 Usage You can find some sample code snippets [here](test/). @@ -98,11 +98,11 @@ type MwTokenName = | 'watch' ``` -### Auxiliary utilities +### 工具函数 Auxiliary utilities -#### `get request` {AxiosInstance} +#### `get request` {Fexios} -Get `Lyla` instance of current MediaWikiApi instance +Get `Fexios` instance of current MediaWikiApi instance #### `MediaWikiApi.normalizeParamValue(params: MwApiParams[keyof MwApiParams]): string | File | undefined` (static) diff --git a/package.json b/package.json index 089102b..b83e60c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "node", "api-wrapper", "typescript", - "axios" + "fetch", + "fetch-api", + "fexios" ], "author": "Dragon-Fish ", "license": "MIT", From d78ced6fea75751e0a0ea0fc97736360d419f185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=BA=E6=99=BA=E7=9A=84=E5=B0=8F=E9=B1=BC=E5=90=9B?= <44761872+dragon-fish@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:52:10 +0000 Subject: [PATCH 12/12] chore: upgrade deps --- package.json | 2 +- pnpm-lock.yaml | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index b83e60c..127df92 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "homepage": "https://github.com/moegirlwiki/wiki-saikou#readme", "dependencies": { "@vue/reactivity": "^3.3.4", - "fexios": "^1.2.0", + "fexios": "^1.3.0", "tslib": "^2.6.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d4f669d..6a9c797 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -9,8 +9,8 @@ dependencies: specifier: ^3.3.4 version: 3.3.4 fexios: - specifier: ^1.2.0 - version: 1.2.0 + specifier: ^1.3.0 + version: 1.3.0 tslib: specifier: ^2.6.0 version: 2.6.0 @@ -1158,8 +1158,9 @@ packages: reusify: 1.0.4 dev: true - /fexios@1.2.0: - resolution: {integrity: sha512-UTXmXvYT/tAVR+Ox3WrdWxJTuriGsh1yPR1/XldM6UFyMMED9pYiDodZydZ1k3rjyoAwd3FDYlcFp0Oiq/h2Xg==} + /fexios@1.3.0: + resolution: {integrity: sha512-OFRMKUkEE/hqIS6fG2WD5tmFTPqpCwhuBu1iwJho41ufHUPsNna+vLokzTuFGk2gMNF1fqy2M0pXwEUqKhza2g==} + engines: {node: ^16.15.0 || >=18.0.0} dev: false /fill-range@7.0.1: