UNPKG

wikibase-edit

Version:

Edit Wikibase from NodeJS

99 lines 3.61 kB
import { stringifyQuery, wait } from '../utils.js'; import checkKnownIssues from './check_known_issues.js'; import { customFetch } from './fetch.js'; import { getSignatureHeaders } from './oauth.js'; import { parseResponseBody } from './parse_response_body.js'; const timeout = 30000; export async function request(method, params) { method ??= 'get'; const { url, body, oauth: oauthTokens, headers, autoRetry = true, httpRequestAgent } = params; let maxlag; if (typeof body === 'object' && 'maxlag' in body) { maxlag = body.maxlag; } let attempts = 1; let bodyStr; if (method === 'post' && body != null) { bodyStr = stringifyQuery(body); headers['Content-Type'] = 'application/x-www-form-urlencoded'; } async function tryRequest() { if (oauthTokens) { const signatureHeaders = getSignatureHeaders({ url, method, data: body, oauthTokens, }); Object.assign(headers, signatureHeaders); } try { const res = await customFetch(url, { method, body: bodyStr, headers, timeout, agent: httpRequestAgent }); return await parseResponseBody(res); } catch (err) { checkKnownIssues(url, err); if (autoRetry === false) throw err; if (errorIsWorthARetry(err)) { const delaySeconds = getRetryDelay(err.headers) * attempts; retryWarn(method, url, err, delaySeconds, attempts++, maxlag); await wait(delaySeconds * 1000); return tryRequest(); } else { err.context ??= {}; err.context.request = { url, body }; throw err; } } } return tryRequest(); } function errorIsWorthARetry(err) { if (errorsWorthARetry.has(err.name) || errorsWorthARetry.has(err.type) || errorsCodeWorthARetry.has(err.code)) return true; // failed-save might be a recoverable error from the server // See https://github.com/maxlath/wikibase-cli/issues/150 if (err.name === 'failed-save') { const { messages } = err.body.error; return !messages.some(isNonRecoverableFailedSave); } if (err.cause) return errorIsWorthARetry(err.cause); return false; } const isNonRecoverableFailedSave = message => message.name.startsWith('wikibase-validator') || nonRecoverableFailedSaveMessageNames.has(message.name); const errorsWorthARetry = new Set([ 'maxlag', 'TimeoutError', 'request-timeout', 'wrong response format', ]); const errorsCodeWorthARetry = new Set([ 'ECONNREFUSED', 'ENETUNREACH', 'ENOTFOUND', 'ETIMEDOUT', 'UND_ERR_CONNECT_TIMEOUT', ]); const nonRecoverableFailedSaveMessageNames = new Set([ 'protectedpagetext', 'permissionserrors', ]); const defaultRetryDelay = 5; function getRetryDelay(headers) { const retryAfterSeconds = headers?.['retry-after']; if (/^\d+$/.test(retryAfterSeconds)) return parseInt(retryAfterSeconds); else return defaultRetryDelay; } function retryWarn(method, url, err, delaySeconds, attempts, maxlag) { method = method.toUpperCase(); const maxlagStr = typeof maxlag === 'number' ? `${maxlag}s` : maxlag; console.warn(`[wikibase-edit][WARNING] ${method} ${url} ${err.message}${err.cause ? ` (cause: ${err.cause.message})` : ''} retrying in ${delaySeconds}s (attempt: ${attempts}, maxlag: ${maxlagStr})`); } //# sourceMappingURL=request.js.map