@hugoalh/http-header-retry-after
Version:
A module to handle the HTTP header `Retry-After` according to the specification RFC 9110.
97 lines (96 loc) • 2.77 kB
JavaScript
const regexpDateRFC7231 = /^[A-Z][a-z][a-z], \d\d [A-Z][a-z][a-z] \d\d\d\d \d\d:\d\d:\d\d GMT$/;
const regexpDecimalInteger = /^\d+$/;
/**
* Handle the HTTP header `Retry-After` according to the specification RFC 9110.
*/
export class HTTPHeaderRetryAfter {
get [Symbol.toStringTag]() {
return "HTTPHeaderRetryAfter";
}
#timestamp;
/**
* Initialize.
* @param {number | string | Date | Headers | Response} input Input.
*/
constructor(input) {
if (typeof input === "number") {
if (!(input >= 0 && input <= Number.MAX_SAFE_INTEGER)) {
throw new RangeError(`Parameter \`input\` is not a number which is positive and safe!`);
}
this.#timestamp = new Date(Date.now() + input * 1000);
}
else if (input instanceof Date) {
this.#timestamp = new Date(input);
}
else {
let inputFmt;
if (input instanceof Response) {
inputFmt = input.headers.get("Retry-After") ?? "0";
}
else if (input instanceof Headers) {
inputFmt = input.get("Retry-After") ?? "0";
}
else {
inputFmt = input;
}
if (regexpDateRFC7231.test(inputFmt)) {
this.#timestamp = new Date(inputFmt);
}
else if (regexpDecimalInteger.test(inputFmt)) {
this.#timestamp = new Date(Date.now() + Number(inputFmt) * 1000);
}
else {
throw new SyntaxError(`\`${inputFmt}\` is not a valid HTTP header \`Retry-After\` value!`);
}
}
}
/**
* Get `Date`.
* @returns {Date}
*/
getDate() {
return new Date(this.#timestamp);
}
/**
* Get remain time in milliseconds.
* @returns {number}
*/
getRemainTimeMilliseconds() {
return Math.max(0, this.#timestamp.valueOf() - Date.now());
}
/**
* Get remain time in seconds.
* @returns {number}
*/
getRemainTimeSeconds() {
return (this.getRemainTimeMilliseconds() / 1000);
}
/**
* Stringify.
* @returns {string}
*/
stringify() {
return this.toString();
}
/**
* Convert to string.
* @returns {string}
*/
toString() {
return this.#timestamp.toUTCString();
}
/**
* Initialize in safe way.
* @param {number | string | Date | Headers | Response} input Input.
* @returns {HTTPHeaderRetryAfter | null}
*/
static parseSafe(input) {
try {
return new this(input);
}
catch {
return null;
}
}
}
export default HTTPHeaderRetryAfter;