New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

xhook

Package Overview
Dependencies
Maintainers
2
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

xhook - npm Package Compare versions

Comparing version

to
1.6.0

.husky/pre-commit

407

dist/xhook.js

@@ -1,19 +0,6 @@

//XHook - v1.5.5 - https://github.com/jpillora/xhook
//Jaime Pillora <dev@jpillora.com> - MIT Copyright 2022
//XHook - v1.6.0 - https://github.com/jpillora/xhook
//Jaime Pillora <dev@jpillora.com> - MIT Copyright 2023
var xhook = (function () {
'use strict';
//if required, add 'indexOf' method to Array
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(item) {
for (let i = 0; i < this.length; i++) {
const x = this[i];
if (x === item) {
return i;
}
}
return -1;
};
}
const slice = (o, n) => Array.prototype.slice.call(o, n);

@@ -35,16 +22,2 @@

//find IE version
const useragent =
typeof navigator !== "undefined" && navigator["useragent"]
? navigator.userAgent
: "";
let msie = null;
if (
/msie (\d+)/.test(useragent.toLowerCase()) ||
/trident\/.*; rv:(\d+)/.test(useragent.toLowerCase())
) {
msie = parseInt(RegExp.$1, 10);
}
const windowRef = result;

@@ -59,3 +32,3 @@ const documentRef = result.document;

const mergeObjects = function(src, dst) {
const mergeObjects = function (src, dst) {
for (let k in src) {

@@ -74,5 +47,5 @@ if (depricatedProp(k)) {

//proxy events from one emitter to another
const proxyEvents = function(events, src, dst) {
const proxyEvents = function (events, src, dst) {
const p = event =>
function(e) {
function (e) {
const clone = {};

@@ -99,3 +72,3 @@ //copies event, with dst emitter inplace of src

//create fake event
const fakeEvent = function(type) {
const fakeEvent = function (type) {
if (documentRef && documentRef.createEventObject != null) {

@@ -116,3 +89,3 @@ const msieEventObject = documentRef.createEventObject();

//tiny event emitter
const EventEmitter = function(nodeStyle) {
const EventEmitter = function (nodeStyle) {
//private

@@ -123,3 +96,3 @@ let events = {};

const emitter = {};
emitter.addEventListener = function(event, callback, i) {
emitter.addEventListener = function (event, callback, i) {
events[event] = listeners(event);

@@ -132,3 +105,3 @@ if (events[event].indexOf(callback) >= 0) {

};
emitter.removeEventListener = function(event, callback) {
emitter.removeEventListener = function (event, callback) {
//remove all

@@ -150,3 +123,3 @@ if (event === undefined) {

};
emitter.dispatchEvent = function() {
emitter.dispatchEvent = function () {
const args = slice(arguments);

@@ -174,4 +147,4 @@ const event = args.shift();

emitter.fire = emitter.dispatchEvent;
emitter.once = function(e, fn) {
var fire = function() {
emitter.once = function (e, fn) {
var fire = function () {
emitter.off(e, fire);

@@ -189,29 +162,43 @@ return fn.apply(null, arguments);

//helper
const convert = function(h, dest) {
let name;
const CRLF = "\r\n";
const objectToString = function (headersObj) {
const entries = Object.entries(headersObj);
const headers = entries.map(([name, value]) => {
return `${name.toLowerCase()}: ${value}`;
});
return headers.join(CRLF);
};
const stringToObject = function (headersString, dest) {
const headers = headersString.split(CRLF);
if (dest == null) {
dest = {};
}
switch (typeof h) {
case "object":
var headers = [];
for (let k in h) {
const v = h[k];
name = k.toLowerCase();
headers.push(`${name}:\t${v}`);
for (let header of headers) {
if (/([^:]+):\s*(.+)/.test(header)) {
const name = RegExp.$1 != null ? RegExp.$1.toLowerCase() : undefined;
const value = RegExp.$2;
if (dest[name] == null) {
dest[name] = value;
}
return headers.join("\n") + "\n";
case "string":
headers = h.split("\n");
for (let header of Array.from(headers)) {
if (/([^:]+):\s*(.+)/.test(header)) {
name = RegExp.$1 != null ? RegExp.$1.toLowerCase() : undefined;
const value = RegExp.$2;
if (dest[name] == null) {
dest[name] = value;
}
}
}
return dest;
}
}
return dest;
};
const convert = function (headers, dest) {
switch (typeof headers) {
case "object": {
return objectToString(headers);
}
case "string": {
return stringToObject(headers, dest);
}
}
return [];

@@ -232,3 +219,3 @@ };

//xhook's XMLHttpRequest
const Xhook$1 = function() {
const Xhook$1 = function () {
const ABORTED = -1;

@@ -250,7 +237,7 @@ const xhr = new Native$1();

//read results from real xhr into response
const readHead = function() {
const readHead = function () {
// Accessing attributes on an aborted xhr object will
// throw an 'c00c023f error' in IE9 and lower, don't touch it.
response.status = status || xhr.status;
if (status !== ABORTED || !(msie < 10)) {
if (status !== ABORTED) {
response.statusText = xhr.statusText;

@@ -271,3 +258,3 @@ }

const readBody = function() {
const readBody = function () {
//https://xhr.spec.whatwg.org/

@@ -297,3 +284,3 @@ if (!xhr.responseType || xhr.responseType === "text") {

//write response into facade xhr
const writeHead = function() {
const writeHead = function () {
facade.status = response.status;

@@ -303,3 +290,3 @@ facade.statusText = response.statusText;

const writeBody = function() {
const writeBody = function () {
if ("text" in response) {

@@ -319,3 +306,3 @@ facade.responseText = response.text;

const emitFinal = function() {
const emitFinal = function () {
if (!hasError) {

@@ -331,3 +318,3 @@ facade.dispatchEvent("load", {});

//ensure ready state 0 through 4 is handled
const emitReadyState = function(n) {
const emitReadyState = function (n) {
while (n > currentState && currentState < 4) {

@@ -360,3 +347,3 @@ facade.readyState = ++currentState;

//control facade ready state
const setReadyState = function(n) {
const setReadyState = function (n) {
//emit events until readyState reaches 4

@@ -369,3 +356,3 @@ if (n !== 4) {

const afterHooks = hooks.listeners("after");
var process = function() {
var process = function () {
if (afterHooks.length > 0) {

@@ -397,3 +384,3 @@ //execute each 'before' hook one at a time

// Handle the underlying ready state
xhr.onreadystatechange = function(event) {
xhr.onreadystatechange = function (event) {
//pull status and headers

@@ -416,3 +403,3 @@ try {

//mark this xhr as errored
const hasErrorHandler = function() {
const hasErrorHandler = function () {
hasError = true;

@@ -424,3 +411,3 @@ };

// progress means we're current downloading...
facade.addEventListener("progress", function(event) {
facade.addEventListener("progress", function (event) {
if (currentState < 3) {

@@ -446,3 +433,3 @@ setReadyState(3);

facade.open = function(method, url, async, user, pass) {
facade.open = function (method, url, async, user, pass) {
// Initailize empty XHR facade

@@ -468,3 +455,3 @@ currentState = 0;

facade.send = function(body) {
facade.send = function (body) {
//read xhr settings before hooking

@@ -480,3 +467,3 @@ let k, modk;

request.body = body;
const send = function() {
const send = function () {
//proxy all events from real xhr to facade

@@ -525,3 +512,3 @@ proxyEvents(COMMON_EVENTS, xhr, facade);

//process beforeHooks sequentially
var process = function() {
var process = function () {
if (!beforeHooks.length) {

@@ -531,3 +518,3 @@ return send();

//go to next hook OR optionally provide response
const done = function(userResponse) {
const done = function (userResponse) {
//break chain - provide dummy response (readyState 4)

@@ -550,3 +537,3 @@ if (

//specifically provide headers (readyState 2)
done.head = function(userResponse) {
done.head = function (userResponse) {
mergeObjects(userResponse, response);

@@ -556,3 +543,3 @@ setReadyState(2);

//specifically provide partial text (responseText readyState 3)
done.progress = function(userResponse) {
done.progress = function (userResponse) {
mergeObjects(userResponse, response);

@@ -579,3 +566,3 @@ setReadyState(3);

facade.abort = function() {
facade.abort = function () {
status = ABORTED;

@@ -589,3 +576,3 @@ if (transiting) {

facade.setRequestHeader = function(header, value) {
facade.setRequestHeader = function (header, value) {
//the first header set is used for all future case-alternatives of 'name'

@@ -609,3 +596,3 @@ const lName = header != null ? header.toLowerCase() : undefined;

if (xhr.overrideMimeType) {
facade.overrideMimeType = function() {
facade.overrideMimeType = function () {
xhr.overrideMimeType.apply(xhr, arguments);

@@ -657,113 +644,153 @@ };

Native: Native$1,
Xhook: Xhook$1
Xhook: Xhook$1,
};
//browser's fetch
const Native = windowRef.fetch;
/******************************************************************************
Copyright (c) Microsoft Corporation.
//xhook's fetch
const Xhook = function(url, options) {
if (options == null) {
options = { headers: {} };
}
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
let request = null;
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
if (url instanceof Request) {
request = url;
} else {
options.url = url;
}
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
const beforeHooks = hooks.listeners("before");
const afterHooks = hooks.listeners("after");
return new Promise(function(resolve, reject) {
let fullfiled = resolve;
const getRequest = function() {
if (options.headers) {
options.headers = new Headers(options.headers);
}
if (!request) {
request = new Request(options.url, options);
}
return mergeObjects(options, request);
};
var processAfter = function(response) {
if (!afterHooks.length) {
return fullfiled(response);
}
const hook = afterHooks.shift();
if (hook.length === 2) {
hook(getRequest(), response);
return processAfter(response);
} else if (hook.length === 3) {
return hook(getRequest(), response, processAfter);
} else {
return processAfter(response);
}
};
const done = function(userResponse) {
if (userResponse !== undefined) {
const response = new Response(
userResponse.body || userResponse.text,
userResponse
);
resolve(response);
processAfter(response);
return;
}
//continue processing until no hooks left
processBefore();
};
var processBefore = function() {
if (!beforeHooks.length) {
send();
return;
}
const hook = beforeHooks.shift();
if (hook.length === 1) {
return done(hook(options));
} else if (hook.length === 2) {
return hook(getRequest(), done);
}
};
var send = () =>
Native(getRequest())
.then(response => processAfter(response))
.catch(function(err) {
fullfiled = reject;
processAfter(err);
return reject(err);
});
processBefore();
});
//browser's fetch
const Native = windowRef.fetch;
function copyToObjFromRequest(req) {
const copyedKeys = [
"method",
"headers",
"body",
"mode",
"credentials",
"cache",
"redirect",
"referrer",
"referrerPolicy",
"integrity",
"keepalive",
"signal",
"url",
];
let copyedObj = {};
copyedKeys.forEach(key => (copyedObj[key] = req[key]));
return copyedObj;
}
function covertHeaderToPlainObj(headers) {
if (headers instanceof Headers) {
return covertTDAarryToObj([...headers.entries()]);
}
if (Array.isArray(headers)) {
return covertTDAarryToObj(headers);
}
return headers;
}
function covertTDAarryToObj(input) {
return input.reduce((prev, [key, value]) => {
prev[key] = value;
return prev;
}, {});
}
/**
* if fetch(hacked by Xhook) accept a Request as a first parameter, it will be destrcuted to a plain object.
* Finally the whole network request was convert to fectch(Request.url, other options)
*/
const Xhook = function (input, init = { headers: {} }) {
let options = Object.assign(Object.assign({}, init), { isFetch: true });
if (input instanceof Request) {
const requestObj = copyToObjFromRequest(input);
const prevHeaders = Object.assign(Object.assign({}, covertHeaderToPlainObj(requestObj.headers)), covertHeaderToPlainObj(options.headers));
options = Object.assign(Object.assign(Object.assign({}, requestObj), init), { headers: prevHeaders, acceptedRequest: true });
}
else {
options.url = input;
}
const beforeHooks = hooks.listeners("before");
const afterHooks = hooks.listeners("after");
return new Promise(function (resolve, reject) {
let fullfiled = resolve;
const processAfter = function (response) {
if (!afterHooks.length) {
return fullfiled(response);
}
const hook = afterHooks.shift();
if (hook.length === 2) {
hook(options, response);
return processAfter(response);
}
else if (hook.length === 3) {
return hook(options, response, processAfter);
}
else {
return processAfter(response);
}
};
const done = function (userResponse) {
if (userResponse !== undefined) {
const response = new Response(userResponse.body || userResponse.text, userResponse);
resolve(response);
processAfter(response);
return;
}
//continue processing until no hooks left
processBefore();
};
const processBefore = function () {
if (!beforeHooks.length) {
send();
return;
}
const hook = beforeHooks.shift();
if (hook.length === 1) {
return done(hook(options));
}
else if (hook.length === 2) {
return hook(options, done);
}
};
const send = () => {
const { url, isFetch, acceptedRequest } = options, restInit = __rest(options, ["url", "isFetch", "acceptedRequest"]);
Native(url, restInit)
.then(response => processAfter(response))
.catch(function (err) {
fullfiled = reject;
processAfter(err);
return reject(err);
});
};
processBefore();
});
};
//patch interface
var fetch = {
patch() {
if (Native) {
windowRef.fetch = Xhook;
}
},
unpatch() {
if (Native) {
windowRef.fetch = Native;
}
},
Native,
Xhook
patch() {
if (Native) {
windowRef.fetch = Xhook;
}
},
unpatch() {
if (Native) {
windowRef.fetch = Native;
}
},
Native,
Xhook,
};

@@ -776,3 +803,3 @@

//modify hooks
xhook.before = function(handler, i) {
xhook.before = function (handler, i) {
if (handler.length < 1 || handler.length > 2) {

@@ -783,3 +810,3 @@ throw "invalid hook";

};
xhook.after = function(handler, i) {
xhook.after = function (handler, i) {
if (handler.length < 2 || handler.length > 3) {

@@ -792,7 +819,7 @@ throw "invalid hook";

//globally enable/disable
xhook.enable = function() {
xhook.enable = function () {
XMLHttpRequest.patch();
fetch.patch();
};
xhook.disable = function() {
xhook.disable = function () {
XMLHttpRequest.unpatch();

@@ -799,0 +826,0 @@ fetch.unpatch();

@@ -1,4 +0,4 @@

//XHook - v1.5.5 - https://github.com/jpillora/xhook
//Jaime Pillora <dev@jpillora.com> - MIT Copyright 2022
var xhook=function(){"use strict";Array.prototype.indexOf||(Array.prototype.indexOf=function(e){for(let t=0;t<this.length;t++){if(this[t]===e)return t}return-1});const e=(e,t)=>Array.prototype.slice.call(e,t);let t=null;"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?t=self:"undefined"!=typeof global?t=global:window&&(t=window);const n="undefined"!=typeof navigator&&navigator.useragent?navigator.userAgent:"";let o=null;(/msie (\d+)/.test(n.toLowerCase())||/trident\/.*; rv:(\d+)/.test(n.toLowerCase()))&&(o=parseInt(RegExp.$1,10));const r=t,s=t.document,a=["load","loadend","loadstart"],i=["progress","abort","error","timeout"],c=e=>["returnValue","totalSize","position"].includes(e),u=function(e,t){for(let n in e){if(c(n))continue;const o=e[n];try{t[n]=o}catch(e){}}return t},l=function(e,t,n){const o=e=>function(o){const r={};for(let e in o){if(c(e))continue;const s=o[e];r[e]=s===t?n:s}return n.dispatchEvent(e,r)};for(let r of Array.from(e))n._has(r)&&(t[`on${r}`]=o(r))},d=function(e){if(s&&null!=s.createEventObject){const t=s.createEventObject();return t.type=e,t}try{return new Event(e)}catch(t){return{type:e}}},f=function(t){let n={};const o=e=>n[e]||[],r={addEventListener:function(e,t,r){n[e]=o(e),n[e].indexOf(t)>=0||(r=void 0===r?n[e].length:r,n[e].splice(r,0,t))},removeEventListener:function(e,t){if(void 0===e)return void(n={});void 0===t&&(n[e]=[]);const r=o(e).indexOf(t);-1!==r&&o(e).splice(r,1)},dispatchEvent:function(){const n=e(arguments),s=n.shift();t||(n[0]=u(n[0],d(s)));const a=r[`on${s}`];a&&a.apply(r,n);const i=o(s).concat(o("*"));for(let e=0;e<i.length;e++){i[e].apply(r,n)}},_has:e=>!(!n[e]&&!r[`on${e}`])};return t&&(r.listeners=t=>e(o(t)),r.on=r.addEventListener,r.off=r.removeEventListener,r.fire=r.dispatchEvent,r.once=function(e,t){var n=function(){return r.off(e,n),t.apply(null,arguments)};return r.on(e,n)},r.destroy=()=>n={}),r};var p=function(e,t){let n;switch(null==t&&(t={}),typeof e){case"object":var o=[];for(let t in e){const r=e[t];n=t.toLowerCase(),o.push(`${n}:\t${r}`)}return o.join("\n")+"\n";case"string":o=e.split("\n");for(let e of Array.from(o))if(/([^:]+):\s*(.+)/.test(e)){n=null!=RegExp.$1?RegExp.$1.toLowerCase():void 0;const e=RegExp.$2;null==t[n]&&(t[n]=e)}return t}return[]};const h=f(!0),v=e=>void 0===e?null:e,y=r.XMLHttpRequest,E=function(){const e=new y,t={};let n,r,s,c=null;var d=0;const E=function(){if(s.status=c||e.status,-1===c&&o<10||(s.statusText=e.statusText),-1===c);else{const t=p(e.getAllResponseHeaders());for(let e in t){const n=t[e];if(!s.headers[e]){const t=e.toLowerCase();s.headers[t]=n}}}},g=function(){b.status=s.status,b.statusText=s.statusText},m=function(){n||b.dispatchEvent("load",{}),b.dispatchEvent("loadend",{}),n&&(b.readyState=0)},x=function(e){for(;e>d&&d<4;)b.readyState=++d,1===d&&b.dispatchEvent("loadstart",{}),2===d&&g(),4===d&&(g(),"text"in s&&(b.responseText=s.text),"xml"in s&&(b.responseXML=s.xml),"data"in s&&(b.response=s.data),"finalUrl"in s&&(b.responseURL=s.finalUrl)),b.dispatchEvent("readystatechange",{}),4===d&&(!1===t.async?m():setTimeout(m,0))},L=function(e){if(4!==e)return void x(e);const n=h.listeners("after");var o=function(){if(n.length>0){const e=n.shift();2===e.length?(e(t,s),o()):3===e.length&&t.async?e(t,s,o):o()}else x(4)};o()};var b=f();t.xhr=b,e.onreadystatechange=function(t){try{2===e.readyState&&E()}catch(e){}4===e.readyState&&(r=!1,E(),function(){if(e.responseType&&"text"!==e.responseType)"document"===e.responseType?(s.xml=e.responseXML,s.data=e.responseXML):s.data=e.response;else{s.text=e.responseText,s.data=e.responseText;try{s.xml=e.responseXML}catch(e){}}"responseURL"in e&&(s.finalUrl=e.responseURL)}()),L(e.readyState)};const w=function(){n=!0};b.addEventListener("error",w),b.addEventListener("timeout",w),b.addEventListener("abort",w),b.addEventListener("progress",(function(t){d<3?L(3):e.readyState<=3&&b.dispatchEvent("readystatechange",{})})),"withCredentials"in e&&(b.withCredentials=!1),b.status=0;for(let e of Array.from(i.concat(a)))b[`on${e}`]=null;if(b.open=function(e,o,a,i,c){d=0,n=!1,r=!1,t.headers={},t.headerNames={},t.status=0,t.method=e,t.url=o,t.async=!1!==a,t.user=i,t.pass=c,s={},s.headers={},L(1)},b.send=function(n){let o,c;for(o of["type","timeout","withCredentials"])c="type"===o?"responseType":o,c in b&&(t[o]=b[c]);t.body=n;const d=h.listeners("before");var f=function(){if(!d.length)return function(){for(o of(l(i,e,b),b.upload&&l(i.concat(a),e.upload,b.upload),r=!0,e.open(t.method,t.url,t.async,t.user,t.pass),["type","timeout","withCredentials"]))c="type"===o?"responseType":o,o in t&&(e[c]=t[o]);for(let n in t.headers){const o=t.headers[n];n&&e.setRequestHeader(n,o)}e.send(t.body)}();const n=function(e){if("object"==typeof e&&("number"==typeof e.status||"number"==typeof s.status))return u(e,s),"data"in e||(e.data=e.response||e.text),void L(4);f()};n.head=function(e){u(e,s),L(2)},n.progress=function(e){u(e,s),L(3)};const p=d.shift();1===p.length?n(p(t)):2===p.length&&t.async?p(t,n):n()};f()},b.abort=function(){c=-1,r?e.abort():b.dispatchEvent("abort",{})},b.setRequestHeader=function(e,n){const o=null!=e?e.toLowerCase():void 0,r=t.headerNames[o]=t.headerNames[o]||e;t.headers[r]&&(n=t.headers[r]+", "+n),t.headers[r]=n},b.getResponseHeader=e=>v(s.headers[e?e.toLowerCase():void 0]),b.getAllResponseHeaders=()=>v(p(s.headers)),e.overrideMimeType&&(b.overrideMimeType=function(){e.overrideMimeType.apply(e,arguments)}),e.upload){let e=f();b.upload=e,t.upload=e}return b.UNSENT=0,b.OPENED=1,b.HEADERS_RECEIVED=2,b.LOADING=3,b.DONE=4,b.response="",b.responseText="",b.responseXML=null,b.readyState=0,b.statusText="",b};E.UNSENT=0,E.OPENED=1,E.HEADERS_RECEIVED=2,E.LOADING=3,E.DONE=4;var g={patch(){y&&(r.XMLHttpRequest=E)},unpatch(){y&&(r.XMLHttpRequest=y)},Native:y,Xhook:E};const m=r.fetch,x=function(e,t){null==t&&(t={headers:{}});let n=null;e instanceof Request?n=e:t.url=e;const o=h.listeners("before"),r=h.listeners("after");return new Promise((function(e,s){let a=e;const i=function(){return t.headers&&(t.headers=new Headers(t.headers)),n||(n=new Request(t.url,t)),u(t,n)};var c=function(e){if(!r.length)return a(e);const t=r.shift();return 2===t.length?(t(i(),e),c(e)):3===t.length?t(i(),e,c):c(e)};const l=function(t){if(void 0!==t){const n=new Response(t.body||t.text,t);return e(n),void c(n)}d()};var d=function(){if(!o.length)return void f();const e=o.shift();return 1===e.length?l(e(t)):2===e.length?e(i(),l):void 0},f=()=>m(i()).then((e=>c(e))).catch((function(e){return a=s,c(e),s(e)}));d()}))};var L={patch(){m&&(r.fetch=x)},unpatch(){m&&(r.fetch=m)},Native:m,Xhook:x};const b=h;return b.EventEmitter=f,b.before=function(e,t){if(e.length<1||e.length>2)throw"invalid hook";return b.on("before",e,t)},b.after=function(e,t){if(e.length<2||e.length>3)throw"invalid hook";return b.on("after",e,t)},b.enable=function(){g.patch(),L.patch()},b.disable=function(){g.unpatch(),L.unpatch()},b.XMLHttpRequest=g.Native,b.fetch=L.Native,b.headers=p,b.enable(),b}();
//XHook - v1.6.0 - https://github.com/jpillora/xhook
//Jaime Pillora <dev@jpillora.com> - MIT Copyright 2023
var xhook=function(){"use strict";const e=(e,t)=>Array.prototype.slice.call(e,t);let t=null;"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?t=self:"undefined"!=typeof global?t=global:window&&(t=window);const n=t,r=t.document,o=["load","loadend","loadstart"],s=["progress","abort","error","timeout"],a=e=>["returnValue","totalSize","position"].includes(e),i=function(e,t){for(let n in e){if(a(n))continue;const r=e[n];try{t[n]=r}catch(e){}}return t},c=function(e,t,n){const r=e=>function(r){const o={};for(let e in r){if(a(e))continue;const s=r[e];o[e]=s===t?n:s}return n.dispatchEvent(e,o)};for(let o of Array.from(e))n._has(o)&&(t[`on${o}`]=r(o))},u=function(e){if(r&&null!=r.createEventObject){const t=r.createEventObject();return t.type=e,t}try{return new Event(e)}catch(t){return{type:e}}},l=function(t){let n={};const r=e=>n[e]||[],o={addEventListener:function(e,t,o){n[e]=r(e),n[e].indexOf(t)>=0||(o=void 0===o?n[e].length:o,n[e].splice(o,0,t))},removeEventListener:function(e,t){if(void 0===e)return void(n={});void 0===t&&(n[e]=[]);const o=r(e).indexOf(t);-1!==o&&r(e).splice(o,1)},dispatchEvent:function(){const n=e(arguments),s=n.shift();t||(n[0]=i(n[0],u(s)));const a=o[`on${s}`];a&&a.apply(o,n);const c=r(s).concat(r("*"));for(let e=0;e<c.length;e++){c[e].apply(o,n)}},_has:e=>!(!n[e]&&!o[`on${e}`])};return t&&(o.listeners=t=>e(r(t)),o.on=o.addEventListener,o.off=o.removeEventListener,o.fire=o.dispatchEvent,o.once=function(e,t){var n=function(){return o.off(e,n),t.apply(null,arguments)};return o.on(e,n)},o.destroy=()=>n={}),o};var f=function(e,t){switch(typeof e){case"object":return n=e,Object.entries(n).map((([e,t])=>`${e.toLowerCase()}: ${t}`)).join("\r\n");case"string":return function(e,t){const n=e.split("\r\n");null==t&&(t={});for(let e of n)if(/([^:]+):\s*(.+)/.test(e)){const e=null!=RegExp.$1?RegExp.$1.toLowerCase():void 0,n=RegExp.$2;null==t[e]&&(t[e]=n)}return t}(e,t)}var n;return[]};const d=l(!0),p=e=>void 0===e?null:e,h=n.XMLHttpRequest,y=function(){const e=new h,t={};let n,r,a,u=null;var y=0;const v=function(){if(a.status=u||e.status,-1!==u&&(a.statusText=e.statusText),-1===u);else{const t=f(e.getAllResponseHeaders());for(let e in t){const n=t[e];if(!a.headers[e]){const t=e.toLowerCase();a.headers[t]=n}}}},g=function(){x.status=a.status,x.statusText=a.statusText},E=function(){n||x.dispatchEvent("load",{}),x.dispatchEvent("loadend",{}),n&&(x.readyState=0)},b=function(e){for(;e>y&&y<4;)x.readyState=++y,1===y&&x.dispatchEvent("loadstart",{}),2===y&&g(),4===y&&(g(),"text"in a&&(x.responseText=a.text),"xml"in a&&(x.responseXML=a.xml),"data"in a&&(x.response=a.data),"finalUrl"in a&&(x.responseURL=a.finalUrl)),x.dispatchEvent("readystatechange",{}),4===y&&(!1===t.async?E():setTimeout(E,0))},m=function(e){if(4!==e)return void b(e);const n=d.listeners("after");var r=function(){if(n.length>0){const e=n.shift();2===e.length?(e(t,a),r()):3===e.length&&t.async?e(t,a,r):r()}else b(4)};r()};var x=l();t.xhr=x,e.onreadystatechange=function(t){try{2===e.readyState&&v()}catch(e){}4===e.readyState&&(r=!1,v(),function(){if(e.responseType&&"text"!==e.responseType)"document"===e.responseType?(a.xml=e.responseXML,a.data=e.responseXML):a.data=e.response;else{a.text=e.responseText,a.data=e.responseText;try{a.xml=e.responseXML}catch(e){}}"responseURL"in e&&(a.finalUrl=e.responseURL)}()),m(e.readyState)};const L=function(){n=!0};x.addEventListener("error",L),x.addEventListener("timeout",L),x.addEventListener("abort",L),x.addEventListener("progress",(function(t){y<3?m(3):e.readyState<=3&&x.dispatchEvent("readystatechange",{})})),"withCredentials"in e&&(x.withCredentials=!1),x.status=0;for(let e of Array.from(s.concat(o)))x[`on${e}`]=null;if(x.open=function(e,o,s,i,c){y=0,n=!1,r=!1,t.headers={},t.headerNames={},t.status=0,t.method=e,t.url=o,t.async=!1!==s,t.user=i,t.pass=c,a={},a.headers={},m(1)},x.send=function(n){let u,l;for(u of["type","timeout","withCredentials"])l="type"===u?"responseType":u,l in x&&(t[u]=x[l]);t.body=n;const f=d.listeners("before");var p=function(){if(!f.length)return function(){for(u of(c(s,e,x),x.upload&&c(s.concat(o),e.upload,x.upload),r=!0,e.open(t.method,t.url,t.async,t.user,t.pass),["type","timeout","withCredentials"]))l="type"===u?"responseType":u,u in t&&(e[l]=t[u]);for(let n in t.headers){const r=t.headers[n];n&&e.setRequestHeader(n,r)}e.send(t.body)}();const n=function(e){if("object"==typeof e&&("number"==typeof e.status||"number"==typeof a.status))return i(e,a),"data"in e||(e.data=e.response||e.text),void m(4);p()};n.head=function(e){i(e,a),m(2)},n.progress=function(e){i(e,a),m(3)};const d=f.shift();1===d.length?n(d(t)):2===d.length&&t.async?d(t,n):n()};p()},x.abort=function(){u=-1,r?e.abort():x.dispatchEvent("abort",{})},x.setRequestHeader=function(e,n){const r=null!=e?e.toLowerCase():void 0,o=t.headerNames[r]=t.headerNames[r]||e;t.headers[o]&&(n=t.headers[o]+", "+n),t.headers[o]=n},x.getResponseHeader=e=>p(a.headers[e?e.toLowerCase():void 0]),x.getAllResponseHeaders=()=>p(f(a.headers)),e.overrideMimeType&&(x.overrideMimeType=function(){e.overrideMimeType.apply(e,arguments)}),e.upload){let e=l();x.upload=e,t.upload=e}return x.UNSENT=0,x.OPENED=1,x.HEADERS_RECEIVED=2,x.LOADING=3,x.DONE=4,x.response="",x.responseText="",x.responseXML=null,x.readyState=0,x.statusText="",x};y.UNSENT=0,y.OPENED=1,y.HEADERS_RECEIVED=2,y.LOADING=3,y.DONE=4;var v={patch(){h&&(n.XMLHttpRequest=y)},unpatch(){h&&(n.XMLHttpRequest=h)},Native:h,Xhook:y};const g=n.fetch;function E(e){return e instanceof Headers?b([...e.entries()]):Array.isArray(e)?b(e):e}function b(e){return e.reduce(((e,[t,n])=>(e[t]=n,e)),{})}const m=function(e,t={headers:{}}){let n=Object.assign(Object.assign({},t),{isFetch:!0});if(e instanceof Request){const r=function(e){let t={};return["method","headers","body","mode","credentials","cache","redirect","referrer","referrerPolicy","integrity","keepalive","signal","url"].forEach((n=>t[n]=e[n])),t}(e),o=Object.assign(Object.assign({},E(r.headers)),E(n.headers));n=Object.assign(Object.assign(Object.assign({},r),t),{headers:o,acceptedRequest:!0})}else n.url=e;const r=d.listeners("before"),o=d.listeners("after");return new Promise((function(e,t){let s=e;const a=function(e){if(!o.length)return s(e);const t=o.shift();return 2===t.length?(t(n,e),a(e)):3===t.length?t(n,e,a):a(e)},i=function(t){if(void 0!==t){const n=new Response(t.body||t.text,t);return e(n),void a(n)}c()},c=function(){if(!r.length)return void u();const e=r.shift();return 1===e.length?i(e(n)):2===e.length?e(n,i):void 0},u=()=>{const{url:e,isFetch:r,acceptedRequest:o}=n,i=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(r=Object.getOwnPropertySymbols(e);o<r.length;o++)t.indexOf(r[o])<0&&Object.prototype.propertyIsEnumerable.call(e,r[o])&&(n[r[o]]=e[r[o]])}return n}(n,["url","isFetch","acceptedRequest"]);g(e,i).then((e=>a(e))).catch((function(e){return s=t,a(e),t(e)}))};c()}))};var x={patch(){g&&(n.fetch=m)},unpatch(){g&&(n.fetch=g)},Native:g,Xhook:m};const L=d;return L.EventEmitter=l,L.before=function(e,t){if(e.length<1||e.length>2)throw"invalid hook";return L.on("before",e,t)},L.after=function(e,t){if(e.length<2||e.length>3)throw"invalid hook";return L.on("after",e,t)},L.enable=function(){v.patch(),x.patch()},L.disable=function(){v.unpatch(),x.unpatch()},L.XMLHttpRequest=v.Native,L.fetch=x.Native,L.headers=f,L.enable(),L}();
//# sourceMappingURL=xhook.min.js.map

@@ -1,14 +0,1 @@

//if required, add 'indexOf' method to Array
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(item) {
for (let i = 0; i < this.length; i++) {
const x = this[i];
if (x === item) {
return i;
}
}
return -1;
};
}
const slice = (o, n) => Array.prototype.slice.call(o, n);

@@ -30,16 +17,2 @@

//find IE version
const useragent =
typeof navigator !== "undefined" && navigator["useragent"]
? navigator.userAgent
: "";
let msie = null;
if (
/msie (\d+)/.test(useragent.toLowerCase()) ||
/trident\/.*; rv:(\d+)/.test(useragent.toLowerCase())
) {
msie = parseInt(RegExp.$1, 10);
}
const windowRef = result;

@@ -54,3 +27,3 @@ const documentRef = result.document;

const mergeObjects = function(src, dst) {
const mergeObjects = function (src, dst) {
for (let k in src) {

@@ -69,5 +42,5 @@ if (depricatedProp(k)) {

//proxy events from one emitter to another
const proxyEvents = function(events, src, dst) {
const proxyEvents = function (events, src, dst) {
const p = event =>
function(e) {
function (e) {
const clone = {};

@@ -94,3 +67,3 @@ //copies event, with dst emitter inplace of src

//create fake event
const fakeEvent = function(type) {
const fakeEvent = function (type) {
if (documentRef && documentRef.createEventObject != null) {

@@ -111,3 +84,3 @@ const msieEventObject = documentRef.createEventObject();

//tiny event emitter
const EventEmitter = function(nodeStyle) {
const EventEmitter = function (nodeStyle) {
//private

@@ -118,3 +91,3 @@ let events = {};

const emitter = {};
emitter.addEventListener = function(event, callback, i) {
emitter.addEventListener = function (event, callback, i) {
events[event] = listeners(event);

@@ -127,3 +100,3 @@ if (events[event].indexOf(callback) >= 0) {

};
emitter.removeEventListener = function(event, callback) {
emitter.removeEventListener = function (event, callback) {
//remove all

@@ -145,3 +118,3 @@ if (event === undefined) {

};
emitter.dispatchEvent = function() {
emitter.dispatchEvent = function () {
const args = slice(arguments);

@@ -169,4 +142,4 @@ const event = args.shift();

emitter.fire = emitter.dispatchEvent;
emitter.once = function(e, fn) {
var fire = function() {
emitter.once = function (e, fn) {
var fire = function () {
emitter.off(e, fire);

@@ -184,29 +157,43 @@ return fn.apply(null, arguments);

//helper
const convert = function(h, dest) {
let name;
const CRLF = "\r\n";
const objectToString = function (headersObj) {
const entries = Object.entries(headersObj);
const headers = entries.map(([name, value]) => {
return `${name.toLowerCase()}: ${value}`;
});
return headers.join(CRLF);
};
const stringToObject = function (headersString, dest) {
const headers = headersString.split(CRLF);
if (dest == null) {
dest = {};
}
switch (typeof h) {
case "object":
var headers = [];
for (let k in h) {
const v = h[k];
name = k.toLowerCase();
headers.push(`${name}:\t${v}`);
for (let header of headers) {
if (/([^:]+):\s*(.+)/.test(header)) {
const name = RegExp.$1 != null ? RegExp.$1.toLowerCase() : undefined;
const value = RegExp.$2;
if (dest[name] == null) {
dest[name] = value;
}
return headers.join("\n") + "\n";
case "string":
headers = h.split("\n");
for (let header of Array.from(headers)) {
if (/([^:]+):\s*(.+)/.test(header)) {
name = RegExp.$1 != null ? RegExp.$1.toLowerCase() : undefined;
const value = RegExp.$2;
if (dest[name] == null) {
dest[name] = value;
}
}
}
return dest;
}
}
return dest;
};
const convert = function (headers, dest) {
switch (typeof headers) {
case "object": {
return objectToString(headers);
}
case "string": {
return stringToObject(headers, dest);
}
}
return [];

@@ -227,3 +214,3 @@ };

//xhook's XMLHttpRequest
const Xhook$1 = function() {
const Xhook$1 = function () {
const ABORTED = -1;

@@ -245,7 +232,7 @@ const xhr = new Native$1();

//read results from real xhr into response
const readHead = function() {
const readHead = function () {
// Accessing attributes on an aborted xhr object will
// throw an 'c00c023f error' in IE9 and lower, don't touch it.
response.status = status || xhr.status;
if (status !== ABORTED || !(msie < 10)) {
if (status !== ABORTED) {
response.statusText = xhr.statusText;

@@ -266,3 +253,3 @@ }

const readBody = function() {
const readBody = function () {
//https://xhr.spec.whatwg.org/

@@ -292,3 +279,3 @@ if (!xhr.responseType || xhr.responseType === "text") {

//write response into facade xhr
const writeHead = function() {
const writeHead = function () {
facade.status = response.status;

@@ -298,3 +285,3 @@ facade.statusText = response.statusText;

const writeBody = function() {
const writeBody = function () {
if ("text" in response) {

@@ -314,3 +301,3 @@ facade.responseText = response.text;

const emitFinal = function() {
const emitFinal = function () {
if (!hasError) {

@@ -326,3 +313,3 @@ facade.dispatchEvent("load", {});

//ensure ready state 0 through 4 is handled
const emitReadyState = function(n) {
const emitReadyState = function (n) {
while (n > currentState && currentState < 4) {

@@ -355,3 +342,3 @@ facade.readyState = ++currentState;

//control facade ready state
const setReadyState = function(n) {
const setReadyState = function (n) {
//emit events until readyState reaches 4

@@ -364,3 +351,3 @@ if (n !== 4) {

const afterHooks = hooks.listeners("after");
var process = function() {
var process = function () {
if (afterHooks.length > 0) {

@@ -392,3 +379,3 @@ //execute each 'before' hook one at a time

// Handle the underlying ready state
xhr.onreadystatechange = function(event) {
xhr.onreadystatechange = function (event) {
//pull status and headers

@@ -411,3 +398,3 @@ try {

//mark this xhr as errored
const hasErrorHandler = function() {
const hasErrorHandler = function () {
hasError = true;

@@ -419,3 +406,3 @@ };

// progress means we're current downloading...
facade.addEventListener("progress", function(event) {
facade.addEventListener("progress", function (event) {
if (currentState < 3) {

@@ -441,3 +428,3 @@ setReadyState(3);

facade.open = function(method, url, async, user, pass) {
facade.open = function (method, url, async, user, pass) {
// Initailize empty XHR facade

@@ -463,3 +450,3 @@ currentState = 0;

facade.send = function(body) {
facade.send = function (body) {
//read xhr settings before hooking

@@ -475,3 +462,3 @@ let k, modk;

request.body = body;
const send = function() {
const send = function () {
//proxy all events from real xhr to facade

@@ -520,3 +507,3 @@ proxyEvents(COMMON_EVENTS, xhr, facade);

//process beforeHooks sequentially
var process = function() {
var process = function () {
if (!beforeHooks.length) {

@@ -526,3 +513,3 @@ return send();

//go to next hook OR optionally provide response
const done = function(userResponse) {
const done = function (userResponse) {
//break chain - provide dummy response (readyState 4)

@@ -545,3 +532,3 @@ if (

//specifically provide headers (readyState 2)
done.head = function(userResponse) {
done.head = function (userResponse) {
mergeObjects(userResponse, response);

@@ -551,3 +538,3 @@ setReadyState(2);

//specifically provide partial text (responseText readyState 3)
done.progress = function(userResponse) {
done.progress = function (userResponse) {
mergeObjects(userResponse, response);

@@ -574,3 +561,3 @@ setReadyState(3);

facade.abort = function() {
facade.abort = function () {
status = ABORTED;

@@ -584,3 +571,3 @@ if (transiting) {

facade.setRequestHeader = function(header, value) {
facade.setRequestHeader = function (header, value) {
//the first header set is used for all future case-alternatives of 'name'

@@ -604,3 +591,3 @@ const lName = header != null ? header.toLowerCase() : undefined;

if (xhr.overrideMimeType) {
facade.overrideMimeType = function() {
facade.overrideMimeType = function () {
xhr.overrideMimeType.apply(xhr, arguments);

@@ -652,113 +639,153 @@ };

Native: Native$1,
Xhook: Xhook$1
Xhook: Xhook$1,
};
//browser's fetch
const Native = windowRef.fetch;
/******************************************************************************
Copyright (c) Microsoft Corporation.
//xhook's fetch
const Xhook = function(url, options) {
if (options == null) {
options = { headers: {} };
}
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
let request = null;
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
if (url instanceof Request) {
request = url;
} else {
options.url = url;
}
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
const beforeHooks = hooks.listeners("before");
const afterHooks = hooks.listeners("after");
return new Promise(function(resolve, reject) {
let fullfiled = resolve;
const getRequest = function() {
if (options.headers) {
options.headers = new Headers(options.headers);
}
if (!request) {
request = new Request(options.url, options);
}
return mergeObjects(options, request);
};
var processAfter = function(response) {
if (!afterHooks.length) {
return fullfiled(response);
}
const hook = afterHooks.shift();
if (hook.length === 2) {
hook(getRequest(), response);
return processAfter(response);
} else if (hook.length === 3) {
return hook(getRequest(), response, processAfter);
} else {
return processAfter(response);
}
};
const done = function(userResponse) {
if (userResponse !== undefined) {
const response = new Response(
userResponse.body || userResponse.text,
userResponse
);
resolve(response);
processAfter(response);
return;
}
//continue processing until no hooks left
processBefore();
};
var processBefore = function() {
if (!beforeHooks.length) {
send();
return;
}
const hook = beforeHooks.shift();
if (hook.length === 1) {
return done(hook(options));
} else if (hook.length === 2) {
return hook(getRequest(), done);
}
};
var send = () =>
Native(getRequest())
.then(response => processAfter(response))
.catch(function(err) {
fullfiled = reject;
processAfter(err);
return reject(err);
});
processBefore();
});
//browser's fetch
const Native = windowRef.fetch;
function copyToObjFromRequest(req) {
const copyedKeys = [
"method",
"headers",
"body",
"mode",
"credentials",
"cache",
"redirect",
"referrer",
"referrerPolicy",
"integrity",
"keepalive",
"signal",
"url",
];
let copyedObj = {};
copyedKeys.forEach(key => (copyedObj[key] = req[key]));
return copyedObj;
}
function covertHeaderToPlainObj(headers) {
if (headers instanceof Headers) {
return covertTDAarryToObj([...headers.entries()]);
}
if (Array.isArray(headers)) {
return covertTDAarryToObj(headers);
}
return headers;
}
function covertTDAarryToObj(input) {
return input.reduce((prev, [key, value]) => {
prev[key] = value;
return prev;
}, {});
}
/**
* if fetch(hacked by Xhook) accept a Request as a first parameter, it will be destrcuted to a plain object.
* Finally the whole network request was convert to fectch(Request.url, other options)
*/
const Xhook = function (input, init = { headers: {} }) {
let options = Object.assign(Object.assign({}, init), { isFetch: true });
if (input instanceof Request) {
const requestObj = copyToObjFromRequest(input);
const prevHeaders = Object.assign(Object.assign({}, covertHeaderToPlainObj(requestObj.headers)), covertHeaderToPlainObj(options.headers));
options = Object.assign(Object.assign(Object.assign({}, requestObj), init), { headers: prevHeaders, acceptedRequest: true });
}
else {
options.url = input;
}
const beforeHooks = hooks.listeners("before");
const afterHooks = hooks.listeners("after");
return new Promise(function (resolve, reject) {
let fullfiled = resolve;
const processAfter = function (response) {
if (!afterHooks.length) {
return fullfiled(response);
}
const hook = afterHooks.shift();
if (hook.length === 2) {
hook(options, response);
return processAfter(response);
}
else if (hook.length === 3) {
return hook(options, response, processAfter);
}
else {
return processAfter(response);
}
};
const done = function (userResponse) {
if (userResponse !== undefined) {
const response = new Response(userResponse.body || userResponse.text, userResponse);
resolve(response);
processAfter(response);
return;
}
//continue processing until no hooks left
processBefore();
};
const processBefore = function () {
if (!beforeHooks.length) {
send();
return;
}
const hook = beforeHooks.shift();
if (hook.length === 1) {
return done(hook(options));
}
else if (hook.length === 2) {
return hook(options, done);
}
};
const send = () => {
const { url, isFetch, acceptedRequest } = options, restInit = __rest(options, ["url", "isFetch", "acceptedRequest"]);
Native(url, restInit)
.then(response => processAfter(response))
.catch(function (err) {
fullfiled = reject;
processAfter(err);
return reject(err);
});
};
processBefore();
});
};
//patch interface
var fetch = {
patch() {
if (Native) {
windowRef.fetch = Xhook;
}
},
unpatch() {
if (Native) {
windowRef.fetch = Native;
}
},
Native,
Xhook
patch() {
if (Native) {
windowRef.fetch = Xhook;
}
},
unpatch() {
if (Native) {
windowRef.fetch = Native;
}
},
Native,
Xhook,
};

@@ -771,3 +798,3 @@

//modify hooks
xhook.before = function(handler, i) {
xhook.before = function (handler, i) {
if (handler.length < 1 || handler.length > 2) {

@@ -778,3 +805,3 @@ throw "invalid hook";

};
xhook.after = function(handler, i) {
xhook.after = function (handler, i) {
if (handler.length < 2 || handler.length > 3) {

@@ -787,7 +814,7 @@ throw "invalid hook";

//globally enable/disable
xhook.enable = function() {
xhook.enable = function () {
XMLHttpRequest.patch();
fetch.patch();
};
xhook.disable = function() {
xhook.disable = function () {
XMLHttpRequest.unpatch();

@@ -794,0 +821,0 @@ fetch.unpatch();

'use strict';
//if required, add 'indexOf' method to Array
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(item) {
for (let i = 0; i < this.length; i++) {
const x = this[i];
if (x === item) {
return i;
}
}
return -1;
};
}
const slice = (o, n) => Array.prototype.slice.call(o, n);

@@ -32,16 +19,2 @@

//find IE version
const useragent =
typeof navigator !== "undefined" && navigator["useragent"]
? navigator.userAgent
: "";
let msie = null;
if (
/msie (\d+)/.test(useragent.toLowerCase()) ||
/trident\/.*; rv:(\d+)/.test(useragent.toLowerCase())
) {
msie = parseInt(RegExp.$1, 10);
}
const windowRef = result;

@@ -56,3 +29,3 @@ const documentRef = result.document;

const mergeObjects = function(src, dst) {
const mergeObjects = function (src, dst) {
for (let k in src) {

@@ -71,5 +44,5 @@ if (depricatedProp(k)) {

//proxy events from one emitter to another
const proxyEvents = function(events, src, dst) {
const proxyEvents = function (events, src, dst) {
const p = event =>
function(e) {
function (e) {
const clone = {};

@@ -96,3 +69,3 @@ //copies event, with dst emitter inplace of src

//create fake event
const fakeEvent = function(type) {
const fakeEvent = function (type) {
if (documentRef && documentRef.createEventObject != null) {

@@ -113,3 +86,3 @@ const msieEventObject = documentRef.createEventObject();

//tiny event emitter
const EventEmitter = function(nodeStyle) {
const EventEmitter = function (nodeStyle) {
//private

@@ -120,3 +93,3 @@ let events = {};

const emitter = {};
emitter.addEventListener = function(event, callback, i) {
emitter.addEventListener = function (event, callback, i) {
events[event] = listeners(event);

@@ -129,3 +102,3 @@ if (events[event].indexOf(callback) >= 0) {

};
emitter.removeEventListener = function(event, callback) {
emitter.removeEventListener = function (event, callback) {
//remove all

@@ -147,3 +120,3 @@ if (event === undefined) {

};
emitter.dispatchEvent = function() {
emitter.dispatchEvent = function () {
const args = slice(arguments);

@@ -171,4 +144,4 @@ const event = args.shift();

emitter.fire = emitter.dispatchEvent;
emitter.once = function(e, fn) {
var fire = function() {
emitter.once = function (e, fn) {
var fire = function () {
emitter.off(e, fire);

@@ -186,29 +159,43 @@ return fn.apply(null, arguments);

//helper
const convert = function(h, dest) {
let name;
const CRLF = "\r\n";
const objectToString = function (headersObj) {
const entries = Object.entries(headersObj);
const headers = entries.map(([name, value]) => {
return `${name.toLowerCase()}: ${value}`;
});
return headers.join(CRLF);
};
const stringToObject = function (headersString, dest) {
const headers = headersString.split(CRLF);
if (dest == null) {
dest = {};
}
switch (typeof h) {
case "object":
var headers = [];
for (let k in h) {
const v = h[k];
name = k.toLowerCase();
headers.push(`${name}:\t${v}`);
for (let header of headers) {
if (/([^:]+):\s*(.+)/.test(header)) {
const name = RegExp.$1 != null ? RegExp.$1.toLowerCase() : undefined;
const value = RegExp.$2;
if (dest[name] == null) {
dest[name] = value;
}
return headers.join("\n") + "\n";
case "string":
headers = h.split("\n");
for (let header of Array.from(headers)) {
if (/([^:]+):\s*(.+)/.test(header)) {
name = RegExp.$1 != null ? RegExp.$1.toLowerCase() : undefined;
const value = RegExp.$2;
if (dest[name] == null) {
dest[name] = value;
}
}
}
return dest;
}
}
return dest;
};
const convert = function (headers, dest) {
switch (typeof headers) {
case "object": {
return objectToString(headers);
}
case "string": {
return stringToObject(headers, dest);
}
}
return [];

@@ -229,3 +216,3 @@ };

//xhook's XMLHttpRequest
const Xhook$1 = function() {
const Xhook$1 = function () {
const ABORTED = -1;

@@ -247,7 +234,7 @@ const xhr = new Native$1();

//read results from real xhr into response
const readHead = function() {
const readHead = function () {
// Accessing attributes on an aborted xhr object will
// throw an 'c00c023f error' in IE9 and lower, don't touch it.
response.status = status || xhr.status;
if (status !== ABORTED || !(msie < 10)) {
if (status !== ABORTED) {
response.statusText = xhr.statusText;

@@ -268,3 +255,3 @@ }

const readBody = function() {
const readBody = function () {
//https://xhr.spec.whatwg.org/

@@ -294,3 +281,3 @@ if (!xhr.responseType || xhr.responseType === "text") {

//write response into facade xhr
const writeHead = function() {
const writeHead = function () {
facade.status = response.status;

@@ -300,3 +287,3 @@ facade.statusText = response.statusText;

const writeBody = function() {
const writeBody = function () {
if ("text" in response) {

@@ -316,3 +303,3 @@ facade.responseText = response.text;

const emitFinal = function() {
const emitFinal = function () {
if (!hasError) {

@@ -328,3 +315,3 @@ facade.dispatchEvent("load", {});

//ensure ready state 0 through 4 is handled
const emitReadyState = function(n) {
const emitReadyState = function (n) {
while (n > currentState && currentState < 4) {

@@ -357,3 +344,3 @@ facade.readyState = ++currentState;

//control facade ready state
const setReadyState = function(n) {
const setReadyState = function (n) {
//emit events until readyState reaches 4

@@ -366,3 +353,3 @@ if (n !== 4) {

const afterHooks = hooks.listeners("after");
var process = function() {
var process = function () {
if (afterHooks.length > 0) {

@@ -394,3 +381,3 @@ //execute each 'before' hook one at a time

// Handle the underlying ready state
xhr.onreadystatechange = function(event) {
xhr.onreadystatechange = function (event) {
//pull status and headers

@@ -413,3 +400,3 @@ try {

//mark this xhr as errored
const hasErrorHandler = function() {
const hasErrorHandler = function () {
hasError = true;

@@ -421,3 +408,3 @@ };

// progress means we're current downloading...
facade.addEventListener("progress", function(event) {
facade.addEventListener("progress", function (event) {
if (currentState < 3) {

@@ -443,3 +430,3 @@ setReadyState(3);

facade.open = function(method, url, async, user, pass) {
facade.open = function (method, url, async, user, pass) {
// Initailize empty XHR facade

@@ -465,3 +452,3 @@ currentState = 0;

facade.send = function(body) {
facade.send = function (body) {
//read xhr settings before hooking

@@ -477,3 +464,3 @@ let k, modk;

request.body = body;
const send = function() {
const send = function () {
//proxy all events from real xhr to facade

@@ -522,3 +509,3 @@ proxyEvents(COMMON_EVENTS, xhr, facade);

//process beforeHooks sequentially
var process = function() {
var process = function () {
if (!beforeHooks.length) {

@@ -528,3 +515,3 @@ return send();

//go to next hook OR optionally provide response
const done = function(userResponse) {
const done = function (userResponse) {
//break chain - provide dummy response (readyState 4)

@@ -547,3 +534,3 @@ if (

//specifically provide headers (readyState 2)
done.head = function(userResponse) {
done.head = function (userResponse) {
mergeObjects(userResponse, response);

@@ -553,3 +540,3 @@ setReadyState(2);

//specifically provide partial text (responseText readyState 3)
done.progress = function(userResponse) {
done.progress = function (userResponse) {
mergeObjects(userResponse, response);

@@ -576,3 +563,3 @@ setReadyState(3);

facade.abort = function() {
facade.abort = function () {
status = ABORTED;

@@ -586,3 +573,3 @@ if (transiting) {

facade.setRequestHeader = function(header, value) {
facade.setRequestHeader = function (header, value) {
//the first header set is used for all future case-alternatives of 'name'

@@ -606,3 +593,3 @@ const lName = header != null ? header.toLowerCase() : undefined;

if (xhr.overrideMimeType) {
facade.overrideMimeType = function() {
facade.overrideMimeType = function () {
xhr.overrideMimeType.apply(xhr, arguments);

@@ -654,113 +641,153 @@ };

Native: Native$1,
Xhook: Xhook$1
Xhook: Xhook$1,
};
//browser's fetch
const Native = windowRef.fetch;
/******************************************************************************
Copyright (c) Microsoft Corporation.
//xhook's fetch
const Xhook = function(url, options) {
if (options == null) {
options = { headers: {} };
}
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
let request = null;
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
if (url instanceof Request) {
request = url;
} else {
options.url = url;
}
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
const beforeHooks = hooks.listeners("before");
const afterHooks = hooks.listeners("after");
return new Promise(function(resolve, reject) {
let fullfiled = resolve;
const getRequest = function() {
if (options.headers) {
options.headers = new Headers(options.headers);
}
if (!request) {
request = new Request(options.url, options);
}
return mergeObjects(options, request);
};
var processAfter = function(response) {
if (!afterHooks.length) {
return fullfiled(response);
}
const hook = afterHooks.shift();
if (hook.length === 2) {
hook(getRequest(), response);
return processAfter(response);
} else if (hook.length === 3) {
return hook(getRequest(), response, processAfter);
} else {
return processAfter(response);
}
};
const done = function(userResponse) {
if (userResponse !== undefined) {
const response = new Response(
userResponse.body || userResponse.text,
userResponse
);
resolve(response);
processAfter(response);
return;
}
//continue processing until no hooks left
processBefore();
};
var processBefore = function() {
if (!beforeHooks.length) {
send();
return;
}
const hook = beforeHooks.shift();
if (hook.length === 1) {
return done(hook(options));
} else if (hook.length === 2) {
return hook(getRequest(), done);
}
};
var send = () =>
Native(getRequest())
.then(response => processAfter(response))
.catch(function(err) {
fullfiled = reject;
processAfter(err);
return reject(err);
});
processBefore();
});
//browser's fetch
const Native = windowRef.fetch;
function copyToObjFromRequest(req) {
const copyedKeys = [
"method",
"headers",
"body",
"mode",
"credentials",
"cache",
"redirect",
"referrer",
"referrerPolicy",
"integrity",
"keepalive",
"signal",
"url",
];
let copyedObj = {};
copyedKeys.forEach(key => (copyedObj[key] = req[key]));
return copyedObj;
}
function covertHeaderToPlainObj(headers) {
if (headers instanceof Headers) {
return covertTDAarryToObj([...headers.entries()]);
}
if (Array.isArray(headers)) {
return covertTDAarryToObj(headers);
}
return headers;
}
function covertTDAarryToObj(input) {
return input.reduce((prev, [key, value]) => {
prev[key] = value;
return prev;
}, {});
}
/**
* if fetch(hacked by Xhook) accept a Request as a first parameter, it will be destrcuted to a plain object.
* Finally the whole network request was convert to fectch(Request.url, other options)
*/
const Xhook = function (input, init = { headers: {} }) {
let options = Object.assign(Object.assign({}, init), { isFetch: true });
if (input instanceof Request) {
const requestObj = copyToObjFromRequest(input);
const prevHeaders = Object.assign(Object.assign({}, covertHeaderToPlainObj(requestObj.headers)), covertHeaderToPlainObj(options.headers));
options = Object.assign(Object.assign(Object.assign({}, requestObj), init), { headers: prevHeaders, acceptedRequest: true });
}
else {
options.url = input;
}
const beforeHooks = hooks.listeners("before");
const afterHooks = hooks.listeners("after");
return new Promise(function (resolve, reject) {
let fullfiled = resolve;
const processAfter = function (response) {
if (!afterHooks.length) {
return fullfiled(response);
}
const hook = afterHooks.shift();
if (hook.length === 2) {
hook(options, response);
return processAfter(response);
}
else if (hook.length === 3) {
return hook(options, response, processAfter);
}
else {
return processAfter(response);
}
};
const done = function (userResponse) {
if (userResponse !== undefined) {
const response = new Response(userResponse.body || userResponse.text, userResponse);
resolve(response);
processAfter(response);
return;
}
//continue processing until no hooks left
processBefore();
};
const processBefore = function () {
if (!beforeHooks.length) {
send();
return;
}
const hook = beforeHooks.shift();
if (hook.length === 1) {
return done(hook(options));
}
else if (hook.length === 2) {
return hook(options, done);
}
};
const send = () => {
const { url, isFetch, acceptedRequest } = options, restInit = __rest(options, ["url", "isFetch", "acceptedRequest"]);
Native(url, restInit)
.then(response => processAfter(response))
.catch(function (err) {
fullfiled = reject;
processAfter(err);
return reject(err);
});
};
processBefore();
});
};
//patch interface
var fetch = {
patch() {
if (Native) {
windowRef.fetch = Xhook;
}
},
unpatch() {
if (Native) {
windowRef.fetch = Native;
}
},
Native,
Xhook
patch() {
if (Native) {
windowRef.fetch = Xhook;
}
},
unpatch() {
if (Native) {
windowRef.fetch = Native;
}
},
Native,
Xhook,
};

@@ -773,3 +800,3 @@

//modify hooks
xhook.before = function(handler, i) {
xhook.before = function (handler, i) {
if (handler.length < 1 || handler.length > 2) {

@@ -780,3 +807,3 @@ throw "invalid hook";

};
xhook.after = function(handler, i) {
xhook.after = function (handler, i) {
if (handler.length < 2 || handler.length > 3) {

@@ -789,7 +816,7 @@ throw "invalid hook";

//globally enable/disable
xhook.enable = function() {
xhook.enable = function () {
XMLHttpRequest.patch();
fetch.patch();
};
xhook.disable = function() {
xhook.disable = function () {
XMLHttpRequest.unpatch();

@@ -796,0 +823,0 @@ fetch.unpatch();

{
"name": "xhook",
"version": "1.5.5",
"version": "1.6.0",
"description": "Easily intercept and modify XHR request and response",

@@ -12,3 +12,3 @@ "main": "lib/main.js",

"test:server": "http-server --port 8080",
"test:all": "testcafe all tests"
"prepare": "husky install"
},

@@ -47,7 +47,14 @@ "repository": {

"@playwright/test": "^1.24.2",
"@rollup/plugin-typescript": "^9.0.2",
"http-server": "^14.1.1",
"husky": "^8.0.1",
"prettier": "2.7.1",
"rollup": "^2.77.2",
"rollup-plugin-terser": "^7.0.2"
"rollup-plugin-terser": "^7.0.2",
"tslib": "^2.4.1",
"typescript": "^4.8.4"
},
"prettier": {}
"lint-staged": {
"**/*": "prettier --write --ignore-unknown"
}
}

@@ -11,19 +11,19 @@ # XHook

* Cache requests in memory, localStorage, etc.
* Insert authentication headers
* S3 Request Signing, see [S3 Hook](https://github.com/jpillora/s3hook)
* Simulate responses
* Create fake transparent backends for testing purposes
* Sending Error statistics to Google Analytics
* Create a client-side alternative to CORS by offloading requests to an iframe then splicing the response back in, see [XDomain](http://jpillora.com/xdomain)
* Devious practical jokes
* Supports RequiresJS and Browserify
* Preflight GZip compression, see [XZip](http://github.com/jpillora/xzip) (Incomplete)
- Cache requests in memory, localStorage, etc.
- Insert authentication headers
- S3 Request Signing, see [S3 Hook](https://github.com/jpillora/s3hook)
- Simulate responses
- Create fake transparent backends for testing purposes
- Sending Error statistics to Google Analytics
- Create a client-side alternative to CORS by offloading requests to an iframe then splicing the response back in, see [XDomain](http://jpillora.com/xdomain)
- Devious practical jokes
- Supports RequiresJS and Browserify
- Preflight GZip compression, see [XZip](http://github.com/jpillora/xzip) (Incomplete)
## Features
* Intercept and modify XMLHttpRequest ("AJAX") **request** and **response**
* Simulate **responses** transparently
* Backwards compatible `addEventListener` `removeEventListener`
* Backwards compatible user controlled progress (download/upload) events
- Intercept and modify XMLHttpRequest ("AJAX") **request** and **response**
- Simulate **responses** transparently
- Backwards compatible `addEventListener` `removeEventListener`
- Backwards compatible user controlled progress (download/upload) events

@@ -40,19 +40,20 @@ ## Browser Support

:warning: *It's* **important** *to include XHook first as other libraries may store a reference to `XMLHttpRequest` before XHook can patch it*
:warning: _It's_ **important** _to include XHook first as other libraries may store a reference to `XMLHttpRequest` before XHook can patch it_
Using `script` link to load xhook and use it, like so:
``` html
```html
<script src="//unpkg.com/xhook@latest/dist/xhook.min.js"></script>
<script>
xhook.after(function(request, response) {
if(request.url.match(/example\.txt$/))
response.text = response.text.replace(/[aeiou]/g,'z');
});
xhook.after(function (request, response) {
if (request.url.match(/example\.txt$/))
response.text = response.text.replace(/[aeiou]/g, "z");
});
</script>
```
* Development [xhook.js](https://jpillora.com/xhook/dist/xhook.js)
* Production [xhook.min.js](https://jpillora.com/xhook/dist/xhook.min.js)
* CDN (Use `latest` or lock to one of the [available versions](https://github.com/jpillora/xhook/releases))
- Development [xhook.js](https://jpillora.com/xhook/dist/xhook.js)
- Production [xhook.min.js](https://jpillora.com/xhook/dist/xhook.min.js)
- CDN (Use `latest` or lock to one of the [available versions](https://github.com/jpillora/xhook/releases))
We can also install xhook via npm.

@@ -65,8 +66,9 @@

Then use ESM syntax to load xhook.
```js
import xhook from 'xhook';
import xhook from "xhook";
//modify 'responseText' of 'example2.txt'
xhook.after(function(request, response) {
if(request.url.match(/example\.txt$/))
response.text = response.text.replace(/[aeiou]/g,'z');
xhook.after(function (request, response) {
if (request.url.match(/example\.txt$/))
response.text = response.text.replace(/[aeiou]/g, "z");
});

@@ -103,18 +105,18 @@ ```

* `method` (String) (*<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#open()">`open(method,url)`</a>*)
* `url` (String) (*<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#open()">`open(method,url)`</a>*)
* `body` (String) (*<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#send()">`send(body)`</a>*)
* `headers` (Object) (*Contains Name-Value pairs set with <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#setRequestHeader()">`setRequestHeader(name,value)`</a>*)
* `timeout` (Number) *([`timeout`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#timeout))*
* `type` (String) *([`responseType`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#responseType))*
* `withCredentials` (String) *([`withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#withCredentials))*
- `method` (String) (_<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#open()">`open(method,url)`</a>_)
- `url` (String) (_<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#open()">`open(method,url)`</a>_)
- `body` (String) (_<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#send()">`send(body)`</a>_)
- `headers` (Object) (_Contains Name-Value pairs set with <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#setRequestHeader()">`setRequestHeader(name,value)`</a>_)
- `timeout` (Number) _([`timeout`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#timeout))_
- `type` (String) _([`responseType`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#responseType))_
- `withCredentials` (String) _([`withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#withCredentials))_
### `response` Object
* `status` (Number) **Required when for fake `response`s** *([`status`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#status))*
* `statusText` (String) *([`statusText`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#statusText))*
* `text` (String) *([`responseText`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#responseText))*
* `headers` (Object) (*Contains Name-Value pairs retrieved with <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#getAllResponseHeaders()">`getAllResponseHeaders()`</a>*)
* `xml` (XML) *([`responseXML`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#responseXML))*
* `data` (Varies) *([`response`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#response))*
- `status` (Number) **Required when for fake `response`s** _([`status`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#status))_
- `statusText` (String) _([`statusText`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#statusText))_
- `text` (String) _([`responseText`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#responseText))_
- `headers` (Object) (_Contains Name-Value pairs retrieved with <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#getAllResponseHeaders()">`getAllResponseHeaders()`</a>_)
- `xml` (XML) _([`responseXML`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#responseXML))_
- `data` (Varies) _([`response`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#response))_

@@ -125,5 +127,5 @@ ## Overview

*The dark red `before` hook is returning a `response` object, which will trigger the `after`
hooks, then trigger the appropriate events, so it* **appears** *as if `response` came from
the server.*
_The dark red `before` hook is returning a `response` object, which will trigger the `after`
hooks, then trigger the appropriate events, so it_ **appears** _as if `response` came from
the server._

@@ -140,7 +142,7 @@ ## Reference

* XHook does **not** attempt to resolve any browser compatibility issues. Libraries like jQuery
and https://github.com/ilinsky/xmlhttprequest will attempt to do this. XHook simply proxies to and from `XMLHttpRequest`, so you may use any library
conjunction with XHook, just make sure to load XHook **first**.
- XHook does **not** attempt to resolve any browser compatibility issues. Libraries like jQuery
and https://github.com/ilinsky/xmlhttprequest will attempt to do this. XHook simply proxies to and from `XMLHttpRequest`, so you may use any library
conjunction with XHook, just make sure to load XHook **first**.
* You may use synchronous XHR, though this will cause asynchronous hooks to be **skipped**.
- You may use synchronous XHR, though this will cause asynchronous hooks to be **skipped**.

@@ -147,0 +149,0 @@ ## Contributing

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet