mirror of
https://github.com/swc-project/swc.git
synced 2024-12-22 21:21:31 +03:00
df2a926e9d
swc_ecma_transforms_module: - Preserve semantics of `this` in imported functions. (#1556)
220 lines
7.7 KiB
JavaScript
220 lines
7.7 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
var _nodeFetch = _interopRequireDefault(require("node-fetch"));
|
|
var _abortSignal = require("./misc/AbortSignal");
|
|
var _errors = require("../../errors");
|
|
var _utils = require("../../utils");
|
|
function _classPrivateFieldGet(receiver, privateMap) {
|
|
if (!privateMap.has(receiver)) {
|
|
throw new TypeError("attempted to get private field on non-instance");
|
|
}
|
|
return privateMap.get(receiver).value;
|
|
}
|
|
function _interopRequireDefault(obj) {
|
|
return obj && obj.__esModule ? obj : {
|
|
default: obj
|
|
};
|
|
}
|
|
const headers = [
|
|
"x-ratelimit-limit",
|
|
"x-ratelimit-remaining",
|
|
"x-ratelimit-reset-after",
|
|
"x-ratelimit-reset",
|
|
"via"
|
|
];
|
|
class RequestHandler {
|
|
/**
|
|
* Whether this handler is inactive or not.
|
|
* @return {boolean}
|
|
*/ get inactive() {
|
|
return !_classPrivateFieldGet(this, _queue).remaining && !this._limited;
|
|
}
|
|
/**
|
|
* Whether the rate-limit bucket is currently limited.
|
|
* @return {boolean}
|
|
* @private
|
|
*/ get _limited() {
|
|
return this.remaining <= 0 && Date.now() < this.reset;
|
|
}
|
|
/**
|
|
* The time until the rate-limit bucket resets.
|
|
* @private
|
|
*/ get _untilReset() {
|
|
return this.reset - Date.now();
|
|
}
|
|
/**
|
|
* Makes a route that can be used as a key.
|
|
* Taken from https://github.com/abalabahaha/eris/blob/master/lib/rest/RequestHandler.js#L46-L54.
|
|
* @param {string} method The method.
|
|
* @param {string} url The URL.
|
|
*
|
|
* @returns {string} The created route.
|
|
*/ static makeRoute(method, url) {
|
|
const route = url.replace(/\/([a-z-]+)\/(?:\d{17,19})/g, (match, p)=>[
|
|
"channels",
|
|
"guilds",
|
|
"webhooks"
|
|
].includes(p) ? match : `/${p}/:id`
|
|
).replace(/\/reactions\/[^/]+/g, "/reactions/:id").replace(/\/webhooks\/(\d+)\/[\w-]{64,}/, "webhooks/$1/:token").replace(/\?.*$/, "");
|
|
let ending = ";";
|
|
if (method === "delete" && route.endsWith("/message/:id")) {
|
|
var ref;
|
|
const id = (ref = /\d{16,19}$/.exec(route)) === null || ref === void 0 ? void 0 : ref[0];
|
|
const snowflake = _utils.Snowflake.deconstruct(id);
|
|
if (Date.now() - snowflake.timestamp > 1000 * 60 * 60 * 24 * 14) {
|
|
ending += "deletes-old";
|
|
}
|
|
}
|
|
return route + ending;
|
|
}
|
|
/**
|
|
* Converts the response to usable data
|
|
* @param {Response} res
|
|
* @return {* | Promise<any>}
|
|
*/ static async parseResponse(res) {
|
|
var ref;
|
|
if ((ref = res.headers.get("Content-Type")) === null || ref === void 0 ? void 0 : ref.startsWith("application/json")) {
|
|
return await res.json();
|
|
}
|
|
return res.buffer();
|
|
}
|
|
/**
|
|
* Pushes a new request into the queue.
|
|
* @param {string} url The request URL.
|
|
* @param {Request} request The request data.
|
|
*
|
|
* @return {Promise<*>}
|
|
*/ async push(url, request) {
|
|
await _classPrivateFieldGet(this, _queue).wait();
|
|
try {
|
|
await this.rest.globalTimeout;
|
|
if (this._limited) {
|
|
/**
|
|
* @typedef {Object} RateLimitedData
|
|
* @property {number} limit
|
|
* @property {string} method
|
|
* @property {string} url
|
|
*
|
|
* Emitted whenever a routes rate-lim\it bucket was exceeded.
|
|
* @event RequestHandler#rate-limited
|
|
* @property {RateLimitedData} data The rate-limit data.
|
|
*/ this.rest.client.emit(_utils.ClientEvent.LIMITED, {
|
|
limit: this.limit,
|
|
method: request.method,
|
|
url
|
|
});
|
|
await (0, _utils).sleep(this._untilReset);
|
|
}
|
|
return this._make(url, request);
|
|
} finally{
|
|
_classPrivateFieldGet(this, _queue).next();
|
|
}
|
|
}
|
|
/**
|
|
* Makes a new request to the provided url.
|
|
* @param url The request URL.
|
|
* @param {Request} request The request data.
|
|
* @param {number} [tries] The current try.
|
|
*
|
|
* @return {Promise<*>}
|
|
* @private
|
|
*/ async _make(url, request, tries = 0) {
|
|
const signal = new _abortSignal.AbortSignal();
|
|
const timeout = _utils.Timers.setTimeout(()=>signal.abort()
|
|
, this.rest.options.timeout);
|
|
let res;
|
|
try {
|
|
res = await (0, _nodeFetch).default(url, {
|
|
...request,
|
|
signal
|
|
});
|
|
} catch (e) {
|
|
if (e.name === "AbortError" && tries !== this.rest.options.retries) {
|
|
return this._make(url, options, tries++);
|
|
}
|
|
throw e;
|
|
} finally{
|
|
_utils.Timers.clearTimeout(timeout);
|
|
}
|
|
let _retry = 0;
|
|
if (res.headers) {
|
|
const [limit, remaining, reset, retry, cf] = getHeaders(res, headers), _reset = ~~reset * 1000 + Date.now() + this.rest.options.offset;
|
|
this.remaining = remaining ? ~~remaining : 1;
|
|
this.limit = limit ? ~~limit : Infinity;
|
|
this.reset = reset ? _reset : Date.now();
|
|
if (retry) {
|
|
_retry = ~~reset * (cf ? 1000 : 1 + this.rest.options.offset);
|
|
}
|
|
if (res.headers.get("X-RateLimit-Global")) {
|
|
this.rest.globalTimeout = (0, _utils).sleep(_retry).then(()=>{
|
|
this.api.globalTimeout = null;
|
|
});
|
|
}
|
|
}
|
|
if (res.ok) {
|
|
return RequestHandler.parseResponse(res);
|
|
}
|
|
if (res.status === 429) {
|
|
this.rest.client.emit(_utils.ClientEvent.LIMITED, `Hit a 429 on route: ${this.id}, Retrying After: ${_retry}ms`);
|
|
await (0, _utils).sleep(_retry);
|
|
return this._make(url, request, tries++);
|
|
}
|
|
if (res.status >= 500 && res.status < 600) {
|
|
if (tries !== this.rest.options.retries) {
|
|
return this._make(url, request, tries++);
|
|
}
|
|
throw new _errors.DiscordHTTPError(res.statusText, res.constructor.name, res.status, request.method, url);
|
|
}
|
|
if (res.status >= 400 && res.status < 500) {
|
|
const data = await RequestHandler.parseResponse(res);
|
|
throw new _errors.DiscordAPIError(data.message, data.code, res.status, request.method, url);
|
|
}
|
|
return null;
|
|
}
|
|
/**
|
|
* @param {Rest} rest The REST Manager.
|
|
* @param {string} id The ID of this request handler.
|
|
*/ constructor(rest, id){
|
|
/**
|
|
* Used for sequential requests.
|
|
* @type {AsyncQueue}
|
|
*/ _queue.set(this, {
|
|
writable: true,
|
|
value: new _utils.AsyncQueue()
|
|
});
|
|
/**
|
|
* The REST Manager.
|
|
* @type {Rest}
|
|
*/ this.rest = rest;
|
|
/**
|
|
* The ID of this request handler.
|
|
* @type {string}
|
|
*/ this.id = id;
|
|
/**
|
|
* Timestamp in which the rate-limit will reset.
|
|
* @type {number}
|
|
*/ this.reset = -1;
|
|
/**
|
|
* The remaining requests that can be made.
|
|
* @type {number}
|
|
*/ this.remaining = 1;
|
|
/**
|
|
* The total number of requests that can be made.
|
|
* @type {number}
|
|
*/ this.limit = Infinity;
|
|
}
|
|
}
|
|
exports.RequestHandler = RequestHandler;
|
|
var _queue = new WeakMap();
|
|
/**
|
|
* Bulk fetch headers from a node-fetch response.
|
|
* @param {Response} res The request response.
|
|
* @param {string[]} headers The headers to fetch.
|
|
* @return {string[]} The header values.
|
|
*/ function getHeaders(res, headers1) {
|
|
return headers1.map((headerName)=>res.headers.get(headerName)
|
|
);
|
|
}
|