Comparing version
@@ -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 |
403
es/main.js
@@ -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(); |
403
lib/main.js
'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
190873
25.36%13
44.44%2250
6.18%150
1.35%9
125%