@timwheeler/monkey-fetch
Version:
Monkey-patch library for the native fetch API
135 lines (134 loc) • 6.25 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MonkeyFetch = void 0;
class MonkeyFetch {
constructor() {
this.debug = false;
this.interceptors = {
request: (resource, options) => Promise.resolve([resource, options]),
requestError: (error) => Promise.reject(error),
response: (response) => Promise.resolve(response),
responseError: (response) => Promise.reject(response),
};
this.getCurrentRuntimeContext();
}
/**
* @description Determine the current JS runtime context, either Browser or Node.js
*/
getCurrentRuntimeContext() {
const isBrowserExecutionContext = typeof window !== 'undefined';
this.debugLog(isBrowserExecutionContext ? 'Browser runtime' : 'Node Runtime');
if (isBrowserExecutionContext) {
require('whatwg-fetch');
}
else {
require('./fetch-polyfill');
}
}
/**
* @description Applies the default or user-supplied `request` and/or the `requestError` interceptors
* @param {[(RequestInfo | URL), RequestInit]} args - the request arguments used to create the monkey-patched request
* @returns {Promise<IMonkeyFetchResponse>} - the Promise containing the request arguments after interceptors have been applied
*/
applyRequestInterceptors(args) {
return __awaiter(this, void 0, void 0, function* () {
this.debugLog('Initial Request Args:', args);
const { request, requestError } = this.interceptors;
try {
return request(...args);
}
catch (err) {
return requestError(err);
}
});
}
/**
* @description Returns the monkey-patched promise that was either resolved or rejected
* @param {Function} fetch - the Fetch API for the current JavaScript runtime context
* @param {[(RequestInfo | URL), RequestInit]} args - the request arguments used to create the monkey-patched request
* @returns {Promise<IMonkeyFetchResponse>} - the Promise containing the response with interceptors applied
*/
sendInterceptedRequest(fetch, args) {
return __awaiter(this, void 0, void 0, function* () {
const interceptedRequest = new Request(...args);
try {
const resolvedResponse = yield fetch(interceptedRequest);
resolvedResponse.request = interceptedRequest;
this.debugLog('Intercepted Request:', interceptedRequest);
this.debugLog('Resolved Response:', resolvedResponse);
return resolvedResponse;
}
catch (error) {
error.request = interceptedRequest;
return error;
}
});
}
/**
* @description Applies the default or user-supplied `response` and `responseError` interceptors
* @param {IMonkeyFetchResponse} initialResponse - the initial, unaltered response before interceptors are applied
* @returns {Promise<IMonkeyFetchResponse>} - the response with interceptors applied
*/
applyResponseInterceptors(initialResponse) {
return __awaiter(this, void 0, void 0, function* () {
const { response, responseError } = this.interceptors;
try {
const interceptedResponse = response(initialResponse);
this.debugLog('Intercepted Response:', interceptedResponse);
return yield interceptedResponse;
}
catch (err) {
return yield responseError(err);
}
});
}
/**
* @description Applies all interceptors to the request and response objects
* @param {Function} fetch - the Fetch API for the current JavaScript runtime context
* @param {[(RequestInfo | URL), RequestInit]} args - the request arguments used to create the monkey-patched request
* @returns {Promise<IMonkeyFetchResponse>} - the response with all interceptors applied
*/
applyInterceptors(fetch, ...args) {
return __awaiter(this, void 0, void 0, function* () {
const monkeyFetchRequestOptions = yield this.applyRequestInterceptors(args);
const responseWithoutInterceptors = yield this.sendInterceptedRequest(fetch, monkeyFetchRequestOptions);
return yield this.applyResponseInterceptors(responseWithoutInterceptors);
});
}
/**
* Debugging tool for internal logging
* @param {any} args - Arbitrary arguments to be emitted via logger
* @returns {void}
*/
debugLog(...args) {
if (this.debug) {
console.warn(`[DEBUG] @timwheeler/monkey-fetch | `, ...args);
}
}
/**
* @description Custom, user-supplied configuration that is applied to `MonkeyFetch`
* @param {IMonkeyFetchConfiguration} configuration - Custom configuration applied to all requests and responses
* @returns {void}
*/
configure(configuration) {
for (let configurationKey in configuration) {
if (configurationKey in this.interceptors) {
this.interceptors[configurationKey] = configuration[configurationKey];
}
else {
this[configurationKey] = configuration[configurationKey];
}
}
globalThis.fetch = ((fetch) => (...args) => this.applyInterceptors(fetch, ...args))(globalThis.fetch);
}
}
exports.MonkeyFetch = MonkeyFetch;