@whitesev/utils 2.9.3 → 2.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.umd.js CHANGED
@@ -7,7 +7,7 @@
7
7
  class ColorConversion {
8
8
  /**
9
9
  * 判断是否是16进制颜色
10
- * @param str
10
+ * @param str 十六进制颜色,如`#000000`
11
11
  */
12
12
  isHex(str) {
13
13
  if (typeof str !== "string") {
@@ -22,8 +22,8 @@
22
22
  * 16进制颜色转rgba
23
23
  *
24
24
  * 例如:`#ff0000` 转为 `rgba(123,123,123, 0.4)`
25
- * @param hex
26
- * @param opacity
25
+ * @param hex 十六进制颜色,如`#000000`
26
+ * @param opacity 透明度,0~1
27
27
  */
28
28
  hexToRgba(hex, opacity) {
29
29
  if (!this.isHex(hex)) {
@@ -35,16 +35,16 @@
35
35
  }
36
36
  /**
37
37
  * hex转rgb
38
- * @param str
38
+ * @param hex 十六进制颜色,如`#000000`
39
39
  */
40
- hexToRgb(str) {
41
- if (!this.isHex(str)) {
42
- throw new TypeError(`输入错误的hex:${str}`);
40
+ hexToRgb(hex) {
41
+ if (!this.isHex(hex)) {
42
+ throw new TypeError(`输入错误的hex:${hex}`);
43
43
  }
44
44
  /* replace替换查找的到的字符串 */
45
- str = str.replace("#", "");
45
+ hex = hex.replace("#", "");
46
46
  /* match得到查询数组 */
47
- const hxs = str.match(/../g);
47
+ const hxs = hex.match(/../g);
48
48
  for (let index = 0; index < 3; index++) {
49
49
  const value = parseInt(hxs[index], 16);
50
50
  Reflect.set(hxs, index, value);
@@ -53,9 +53,10 @@
53
53
  }
54
54
  /**
55
55
  * rgb转hex
56
- * @param redValue
57
- * @param greenValue
58
- * @param blueValue
56
+ * @param redValue 红色值
57
+ * @param greenValue 绿色值
58
+ * @param blueValue 蓝色值
59
+ * @returns hex
59
60
  */
60
61
  rgbToHex(redValue, greenValue, blueValue) {
61
62
  /* 验证输入的rgb值是否合法 */
@@ -72,30 +73,36 @@
72
73
  }
73
74
  /**
74
75
  * 获取颜色变暗或亮
75
- * @param color 颜色
76
- * @param level 0~1.0
76
+ * @param color hex颜色,如`#000000`
77
+ * @param level 0~1.0 系数越大,颜色越变暗
77
78
  */
78
79
  getDarkColor(color, level) {
79
80
  if (!this.isHex(color)) {
80
81
  throw new TypeError(`输入错误的hex:${color}`);
81
82
  }
83
+ if (typeof level !== "number") {
84
+ level = Number(level);
85
+ }
82
86
  const rgbc = this.hexToRgb(color);
83
87
  for (let index = 0; index < 3; index++) {
84
88
  const rgbcItemValue = rgbc[index];
85
- const value = Math.floor(Number(rgbcItemValue) * (1 - Number(level)));
89
+ const value = Math.floor(Number(rgbcItemValue) * (1 - level));
86
90
  Reflect.set(rgbc, index, value);
87
91
  }
88
92
  return this.rgbToHex(rgbc[0], rgbc[1], rgbc[2]);
89
93
  }
90
94
  /**
91
95
  * 获取颜色变亮
92
- * @param color 颜色
93
- * @param level 0~1.0
96
+ * @param color hex颜色,如`#000000`
97
+ * @param level 0~1.0 系数越大,颜色越变亮
94
98
  */
95
99
  getLightColor(color, level) {
96
100
  if (!this.isHex(color)) {
97
101
  throw new TypeError(`输入错误的hex:${color}`);
98
102
  }
103
+ if (typeof level !== "number") {
104
+ level = Number(level);
105
+ }
99
106
  const rgbc = this.hexToRgb(color);
100
107
  for (let index = 0; index < 3; index++) {
101
108
  const rgbcItemValue = Number(rgbc[index]);
@@ -717,1001 +724,981 @@
717
724
  }
718
725
  }
719
726
 
720
- /* eslint-disable */
721
- // ==UserScript==
722
- // @name ajaxHooker
723
- // @author cxxjackie
724
- // @version 1.4.8
725
- // @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
726
- // @license GNU LGPL-3.0
727
- // ==/UserScript==
728
-
729
- const ajaxHooker = function () {
730
- const version = "1.4.8";
731
- const hookInst = {
732
- hookFns: [],
733
- filters: [],
734
- };
735
- const win = window.unsafeWindow || document.defaultView || window;
736
- let winAh = win.__ajaxHooker;
737
- const resProto = win.Response.prototype;
738
- const xhrResponses = ["response", "responseText", "responseXML"];
739
- const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
740
- const xhrExtraProps = ["responseType", "timeout", "withCredentials"];
741
- const fetchExtraProps = [
742
- "cache",
743
- "credentials",
744
- "integrity",
745
- "keepalive",
746
- "mode",
747
- "priority",
748
- "redirect",
749
- "referrer",
750
- "referrerPolicy",
751
- "signal",
752
- ];
753
- const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
754
- const getType = {}.toString.call.bind({}.toString);
755
- const getDescriptor = Object.getOwnPropertyDescriptor.bind(Object);
756
- const emptyFn = () => {};
757
- const errorFn = (e) => console.error(e);
758
- function isThenable(obj) {
759
- return obj && ["object", "function"].includes(typeof obj) && typeof obj.then === "function";
760
- }
761
- function catchError(fn, ...args) {
762
- try {
763
- const result = fn(...args);
764
- if (isThenable(result)) return result.then(null, errorFn);
765
- return result;
766
- } catch (err) {
767
- console.error(err);
768
- }
769
- }
770
- function defineProp(obj, prop, getter, setter) {
771
- Object.defineProperty(obj, prop, {
772
- configurable: true,
773
- enumerable: true,
774
- get: getter,
775
- set: setter,
776
- });
777
- }
778
- function readonly(obj, prop, value = obj[prop]) {
779
- defineProp(obj, prop, () => value, emptyFn);
780
- }
781
- function writable(obj, prop, value = obj[prop]) {
782
- Object.defineProperty(obj, prop, {
783
- configurable: true,
784
- enumerable: true,
785
- writable: true,
786
- value: value,
787
- });
788
- }
789
- function parseHeaders(obj) {
790
- const headers = {};
791
- switch (getType(obj)) {
792
- case "[object String]":
793
- for (const line of obj.trim().split(/[\r\n]+/)) {
794
- const [header, value] = line.split(/(?<=^[^:]+)\s*:\s*/);
795
- if (!value) continue;
796
- const lheader = header.toLowerCase();
797
- headers[lheader] = lheader in headers ? `${headers[lheader]}, ${value}` : value;
798
- }
799
- break;
800
- case "[object Headers]":
801
- for (const [key, val] of obj) {
802
- headers[key] = val;
803
- }
804
- break;
805
- case "[object Object]":
806
- return { ...obj };
807
- }
808
- return headers;
809
- }
810
- function stopImmediatePropagation() {
811
- this.ajaxHooker_isStopped = true;
812
- }
813
- class SyncThenable {
814
- then(fn) {
815
- fn && fn();
816
- return new SyncThenable();
817
- }
818
- }
819
- class AHRequest {
820
- constructor(request) {
821
- this.request = request;
822
- this.requestClone = { ...this.request };
823
- }
824
- _recoverRequestKey(key) {
825
- if (key in this.requestClone) this.request[key] = this.requestClone[key];
826
- else delete this.request[key];
827
- }
828
- shouldFilter(filters) {
829
- const { type, url, method, async } = this.request;
830
- return (
831
- filters.length &&
832
- !filters.find((obj) => {
833
- switch (true) {
834
- case obj.type && obj.type !== type:
835
- case getType(obj.url) === "[object String]" && !url.includes(obj.url):
836
- case getType(obj.url) === "[object RegExp]" && !obj.url.test(url):
837
- case obj.method && obj.method.toUpperCase() !== method.toUpperCase():
838
- case "async" in obj && obj.async !== async:
839
- return false;
840
- }
841
- return true;
842
- })
843
- );
844
- }
845
- waitForRequestKeys() {
846
- if (!this.request.async) {
847
- win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
848
- if (this.shouldFilter(filters)) return;
849
- hookFns.forEach((fn) => {
850
- if (getType(fn) === "[object Function]") catchError(fn, this.request);
851
- });
852
- for (const key in this.request) {
853
- if (isThenable(this.request[key])) this._recoverRequestKey(key);
854
- }
855
- });
856
- return new SyncThenable();
857
- }
858
- const promises = [];
859
- const ignoreKeys = new Set(["type", "async", "response"]);
860
- win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
861
- if (this.shouldFilter(filters)) return;
862
- promises.push(
863
- Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(() => {
864
- const requestKeys = [];
865
- for (const key in this.request) !ignoreKeys.has(key) && requestKeys.push(key);
866
- return Promise.all(
867
- requestKeys.map((key) =>
868
- Promise.resolve(this.request[key]).then(
869
- (val) => (this.request[key] = val),
870
- () => this._recoverRequestKey(key)
871
- )
872
- )
873
- );
874
- })
875
- );
876
- });
877
- return Promise.all(promises);
878
- }
879
- waitForResponseKeys(response) {
880
- const responseKeys = this.request.type === "xhr" ? xhrResponses : fetchResponses;
881
- if (!this.request.async) {
882
- if (getType(this.request.response) === "[object Function]") {
883
- catchError(this.request.response, response);
884
- responseKeys.forEach((key) => {
885
- if ("get" in getDescriptor(response, key) || isThenable(response[key])) {
886
- delete response[key];
887
- }
888
- });
889
- }
890
- return new SyncThenable();
891
- }
892
- return Promise.resolve(catchError(this.request.response, response)).then(() =>
893
- Promise.all(
894
- responseKeys.map((key) => {
895
- const descriptor = getDescriptor(response, key);
896
- if (descriptor && "value" in descriptor) {
897
- return Promise.resolve(descriptor.value).then(
898
- (val) => (response[key] = val),
899
- () => delete response[key]
900
- );
901
- } else {
902
- delete response[key];
903
- }
904
- })
905
- )
906
- );
907
- }
908
- }
909
- const proxyHandler = {
910
- get(target, prop) {
911
- const descriptor = getDescriptor(target, prop);
912
- if (descriptor && !descriptor.configurable && !descriptor.writable && !descriptor.get)
913
- return target[prop];
914
- const ah = target.__ajaxHooker;
915
- if (ah && ah.proxyProps) {
916
- if (prop in ah.proxyProps) {
917
- const pDescriptor = ah.proxyProps[prop];
918
- if ("get" in pDescriptor) return pDescriptor.get();
919
- if (typeof pDescriptor.value === "function") return pDescriptor.value.bind(ah);
920
- return pDescriptor.value;
921
- }
922
- if (typeof target[prop] === "function") return target[prop].bind(target);
923
- }
924
- return target[prop];
925
- },
926
- set(target, prop, value) {
927
- const descriptor = getDescriptor(target, prop);
928
- if (descriptor && !descriptor.configurable && !descriptor.writable && !descriptor.set) return true;
929
- const ah = target.__ajaxHooker;
930
- if (ah && ah.proxyProps && prop in ah.proxyProps) {
931
- const pDescriptor = ah.proxyProps[prop];
932
- pDescriptor.set ? pDescriptor.set(value) : (pDescriptor.value = value);
933
- } else {
934
- target[prop] = value;
935
- }
936
- return true;
937
- },
938
- };
939
- class XhrHooker {
940
- constructor(xhr) {
941
- const ah = this;
942
- Object.assign(ah, {
943
- originalXhr: xhr,
944
- proxyXhr: new Proxy(xhr, proxyHandler),
945
- resThenable: new SyncThenable(),
946
- proxyProps: {},
947
- proxyEvents: {},
948
- });
949
- xhr.addEventListener("readystatechange", (e) => {
950
- if (ah.proxyXhr.readyState === 4 && ah.request && typeof ah.request.response === "function") {
951
- const response = {
952
- finalUrl: ah.proxyXhr.responseURL,
953
- status: ah.proxyXhr.status,
954
- responseHeaders: parseHeaders(ah.proxyXhr.getAllResponseHeaders()),
955
- };
956
- const tempValues = {};
957
- for (const key of xhrResponses) {
958
- try {
959
- tempValues[key] = ah.originalXhr[key];
960
- } catch (err) {}
961
- defineProp(
962
- response,
963
- key,
964
- () => {
965
- return (response[key] = tempValues[key]);
966
- },
967
- (val) => {
968
- delete response[key];
969
- response[key] = val;
970
- }
971
- );
972
- }
973
- ah.resThenable = new AHRequest(ah.request).waitForResponseKeys(response).then(() => {
974
- for (const key of xhrResponses) {
975
- ah.proxyProps[key] = {
976
- get: () => {
977
- if (!(key in response)) response[key] = tempValues[key];
978
- return response[key];
979
- },
980
- };
981
- }
982
- });
983
- }
984
- ah.dispatchEvent(e);
985
- });
986
- xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
987
- xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
988
- for (const evt of xhrAsyncEvents) {
989
- const onEvt = "on" + evt;
990
- ah.proxyProps[onEvt] = {
991
- get: () => ah.proxyEvents[onEvt] || null,
992
- set: (val) => ah.addEvent(onEvt, val),
993
- };
994
- }
995
- for (const method of ["setRequestHeader", "addEventListener", "removeEventListener", "open", "send"]) {
996
- ah.proxyProps[method] = { value: ah[method] };
997
- }
998
- }
999
- toJSON() {} // Converting circular structure to JSON
1000
- addEvent(type, event) {
1001
- if (type.startsWith("on")) {
1002
- this.proxyEvents[type] = typeof event === "function" ? event : null;
1003
- } else {
1004
- if (typeof event === "object" && event !== null) event = event.handleEvent;
1005
- if (typeof event !== "function") return;
1006
- this.proxyEvents[type] = this.proxyEvents[type] || new Set();
1007
- this.proxyEvents[type].add(event);
1008
- }
1009
- }
1010
- removeEvent(type, event) {
1011
- if (type.startsWith("on")) {
1012
- this.proxyEvents[type] = null;
1013
- } else {
1014
- if (typeof event === "object" && event !== null) event = event.handleEvent;
1015
- this.proxyEvents[type] && this.proxyEvents[type].delete(event);
1016
- }
1017
- }
1018
- dispatchEvent(e) {
1019
- e.stopImmediatePropagation = stopImmediatePropagation;
1020
- defineProp(e, "target", () => this.proxyXhr);
1021
- defineProp(e, "currentTarget", () => this.proxyXhr);
1022
- defineProp(e, "srcElement", () => this.proxyXhr);
1023
- this.proxyEvents[e.type] &&
1024
- this.proxyEvents[e.type].forEach((fn) => {
1025
- this.resThenable.then(() => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e));
1026
- });
1027
- if (e.ajaxHooker_isStopped) return;
1028
- const onEvent = this.proxyEvents["on" + e.type];
1029
- onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
1030
- }
1031
- setRequestHeader(header, value) {
1032
- this.originalXhr.setRequestHeader(header, value);
1033
- if (!this.request) return;
1034
- const headers = this.request.headers;
1035
- headers[header] = header in headers ? `${headers[header]}, ${value}` : value;
1036
- }
1037
- addEventListener(...args) {
1038
- if (xhrAsyncEvents.includes(args[0])) {
1039
- this.addEvent(args[0], args[1]);
1040
- } else {
1041
- this.originalXhr.addEventListener(...args);
1042
- }
1043
- }
1044
- removeEventListener(...args) {
1045
- if (xhrAsyncEvents.includes(args[0])) {
1046
- this.removeEvent(args[0], args[1]);
1047
- } else {
1048
- this.originalXhr.removeEventListener(...args);
1049
- }
1050
- }
1051
- open(method, url, async = true, ...args) {
1052
- this.request = {
1053
- type: "xhr",
1054
- url: url.toString(),
1055
- method: method.toUpperCase(),
1056
- abort: false,
1057
- headers: {},
1058
- data: null,
1059
- response: null,
1060
- async: !!async,
1061
- };
1062
- this.openArgs = args;
1063
- this.resThenable = new SyncThenable();
1064
- ["responseURL", "readyState", "status", "statusText", ...xhrResponses].forEach((key) => {
1065
- delete this.proxyProps[key];
1066
- });
1067
- return this.originalXhr.open(method, url, async, ...args);
1068
- }
1069
- send(data) {
1070
- const ah = this;
1071
- const xhr = ah.originalXhr;
1072
- const request = ah.request;
1073
- if (!request) return xhr.send(data);
1074
- request.data = data;
1075
- new AHRequest(request).waitForRequestKeys().then(() => {
1076
- if (request.abort) {
1077
- if (typeof request.response === "function") {
1078
- Object.assign(ah.proxyProps, {
1079
- responseURL: { value: request.url },
1080
- readyState: { value: 4 },
1081
- status: { value: 200 },
1082
- statusText: { value: "OK" },
1083
- });
1084
- xhrAsyncEvents.forEach((evt) => xhr.dispatchEvent(new Event(evt)));
1085
- }
1086
- } else {
1087
- xhr.open(request.method, request.url, request.async, ...ah.openArgs);
1088
- for (const header in request.headers) {
1089
- xhr.setRequestHeader(header, request.headers[header]);
1090
- }
1091
- for (const prop of xhrExtraProps) {
1092
- if (prop in request) xhr[prop] = request[prop];
1093
- }
1094
- xhr.send(request.data);
1095
- }
1096
- });
1097
- }
1098
- }
1099
- function fakeXHR() {
1100
- const xhr = new winAh.realXHR();
1101
- if ("__ajaxHooker" in xhr) console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
1102
- xhr.__ajaxHooker = new XhrHooker(xhr);
1103
- return xhr.__ajaxHooker.proxyXhr;
1104
- }
1105
- fakeXHR.prototype = win.XMLHttpRequest.prototype;
1106
- Object.keys(win.XMLHttpRequest).forEach((key) => (fakeXHR[key] = win.XMLHttpRequest[key]));
1107
- function fakeFetch(url, options = {}) {
1108
- if (!url) return winAh.realFetch.call(win, url, options);
1109
- return new Promise(async (resolve, reject) => {
1110
- const init = {};
1111
- if (getType(url) === "[object Request]") {
1112
- init.method = url.method;
1113
- init.headers = url.headers;
1114
- if (url.body) init.body = await url.arrayBuffer();
1115
- for (const prop of fetchExtraProps) init[prop] = url[prop];
1116
- url = url.url;
1117
- }
1118
- url = url.toString();
1119
- Object.assign(init, options);
1120
- init.method = init.method || "GET";
1121
- init.headers = init.headers || {};
1122
- const request = {
1123
- type: "fetch",
1124
- url: url,
1125
- method: init.method.toUpperCase(),
1126
- abort: false,
1127
- headers: parseHeaders(init.headers),
1128
- data: init.body,
1129
- response: null,
1130
- async: true,
1131
- };
1132
- const req = new AHRequest(request);
1133
- await req.waitForRequestKeys();
1134
- if (request.abort) {
1135
- if (typeof request.response === "function") {
1136
- const response = {
1137
- finalUrl: request.url,
1138
- status: 200,
1139
- responseHeaders: {},
1140
- };
1141
- await req.waitForResponseKeys(response);
1142
- const key = fetchResponses.find((k) => k in response);
1143
- let val = response[key];
1144
- if (key === "json" && typeof val === "object") {
1145
- val = catchError(JSON.stringify.bind(JSON), val);
1146
- }
1147
- const res = new Response(val, {
1148
- status: 200,
1149
- statusText: "OK",
1150
- });
1151
- defineProp(res, "type", () => "basic");
1152
- defineProp(res, "url", () => request.url);
1153
- resolve(res);
1154
- } else {
1155
- reject(new DOMException("aborted", "AbortError"));
1156
- }
1157
- return;
1158
- }
1159
- init.method = request.method;
1160
- init.headers = request.headers;
1161
- init.body = request.data;
1162
- for (const prop of fetchExtraProps) {
1163
- if (prop in request) init[prop] = request[prop];
1164
- }
1165
- winAh.realFetch.call(win, request.url, init).then((res) => {
1166
- if (typeof request.response === "function") {
1167
- const response = {
1168
- finalUrl: res.url,
1169
- status: res.status,
1170
- responseHeaders: parseHeaders(res.headers),
1171
- };
1172
- if (res.ok) {
1173
- fetchResponses.forEach(
1174
- (key) =>
1175
- (res[key] = function () {
1176
- if (key in response) return Promise.resolve(response[key]);
1177
- return resProto[key].call(this).then((val) => {
1178
- response[key] = val;
1179
- return req
1180
- .waitForResponseKeys(response)
1181
- .then(() => (key in response ? response[key] : val));
1182
- });
1183
- })
1184
- );
1185
- } else {
1186
- catchError(request.response, response);
1187
- }
1188
- }
1189
- resolve(res);
1190
- }, reject);
1191
- });
1192
- }
1193
- function fakeFetchClone() {
1194
- const descriptors = Object.getOwnPropertyDescriptors(this);
1195
- const res = winAh.realFetchClone.call(this);
1196
- Object.defineProperties(res, descriptors);
1197
- return res;
1198
- }
1199
- winAh = win.__ajaxHooker = winAh || {
1200
- version,
1201
- fakeXHR,
1202
- fakeFetch,
1203
- fakeFetchClone,
1204
- realXHR: win.XMLHttpRequest,
1205
- realFetch: win.fetch,
1206
- realFetchClone: resProto.clone,
1207
- hookInsts: new Set(),
1208
- };
1209
- if (winAh.version !== version) console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
1210
- win.XMLHttpRequest = winAh.fakeXHR;
1211
- win.fetch = winAh.fakeFetch;
1212
- resProto.clone = winAh.fakeFetchClone;
1213
- winAh.hookInsts.add(hookInst);
1214
- // 针对头条、抖音 secsdk.umd.js 的兼容性处理
1215
- class AHFunction extends Function {
1216
- call(thisArg, ...args) {
1217
- if (thisArg && thisArg.__ajaxHooker && thisArg.__ajaxHooker.proxyXhr === thisArg) {
1218
- thisArg = thisArg.__ajaxHooker.originalXhr;
1219
- }
1220
- return Reflect.apply(this, thisArg, args);
1221
- }
1222
- apply(thisArg, args) {
1223
- if (thisArg && thisArg.__ajaxHooker && thisArg.__ajaxHooker.proxyXhr === thisArg) {
1224
- thisArg = thisArg.__ajaxHooker.originalXhr;
1225
- }
1226
- return Reflect.apply(this, thisArg, args || []);
1227
- }
1228
- }
1229
- function hookSecsdk(csrf) {
1230
- Object.setPrototypeOf(csrf.nativeXMLHttpRequestSetRequestHeader, AHFunction.prototype);
1231
- Object.setPrototypeOf(csrf.nativeXMLHttpRequestOpen, AHFunction.prototype);
1232
- Object.setPrototypeOf(csrf.nativeXMLHttpRequestSend, AHFunction.prototype);
1233
- }
1234
- if (win.secsdk) {
1235
- if (win.secsdk.csrf && win.secsdk.csrf.nativeXMLHttpRequestOpen) hookSecsdk(win.secsdk.csrf);
1236
- } else {
1237
- defineProp(win, "secsdk", emptyFn, (secsdk) => {
1238
- delete win.secsdk;
1239
- win.secsdk = secsdk;
1240
- defineProp(secsdk, "csrf", emptyFn, (csrf) => {
1241
- delete secsdk.csrf;
1242
- secsdk.csrf = csrf;
1243
- if (csrf.nativeXMLHttpRequestOpen) hookSecsdk(csrf);
1244
- });
1245
- });
1246
- }
1247
- return {
1248
- hook: (fn) => hookInst.hookFns.push(fn),
1249
- filter: (arr) => {
1250
- if (Array.isArray(arr)) hookInst.filters = arr;
1251
- },
1252
- protect: () => {
1253
- readonly(win, "XMLHttpRequest", winAh.fakeXHR);
1254
- readonly(win, "fetch", winAh.fakeFetch);
1255
- readonly(resProto, "clone", winAh.fakeFetchClone);
1256
- },
1257
- unhook: () => {
1258
- winAh.hookInsts.delete(hookInst);
1259
- if (!winAh.hookInsts.size) {
1260
- writable(win, "XMLHttpRequest", winAh.realXHR);
1261
- writable(win, "fetch", winAh.realFetch);
1262
- writable(resProto, "clone", winAh.realFetchClone);
1263
- delete win.__ajaxHooker;
1264
- }
1265
- },
1266
- };
727
+ /* eslint-disable */
728
+ // ==UserScript==
729
+ // @name ajaxHooker
730
+ // @author cxxjackie
731
+ // @version 1.4.8
732
+ // @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
733
+ // @license GNU LGPL-3.0
734
+ // ==/UserScript==
735
+ const ajaxHooker = function () {
736
+ const version = "1.4.8";
737
+ const hookInst = {
738
+ hookFns: [],
739
+ filters: [],
740
+ };
741
+ const win = window.unsafeWindow || document.defaultView || window;
742
+ let winAh = win.__ajaxHooker;
743
+ const resProto = win.Response.prototype;
744
+ const xhrResponses = ["response", "responseText", "responseXML"];
745
+ const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
746
+ const xhrExtraProps = ["responseType", "timeout", "withCredentials"];
747
+ const fetchExtraProps = [
748
+ "cache",
749
+ "credentials",
750
+ "integrity",
751
+ "keepalive",
752
+ "mode",
753
+ "priority",
754
+ "redirect",
755
+ "referrer",
756
+ "referrerPolicy",
757
+ "signal",
758
+ ];
759
+ const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
760
+ const getType = {}.toString.call.bind({}.toString);
761
+ const getDescriptor = Object.getOwnPropertyDescriptor.bind(Object);
762
+ const emptyFn = () => { };
763
+ const errorFn = (e) => console.error(e);
764
+ function isThenable(obj) {
765
+ return obj && ["object", "function"].includes(typeof obj) && typeof obj.then === "function";
766
+ }
767
+ function catchError(fn, ...args) {
768
+ try {
769
+ const result = fn(...args);
770
+ if (isThenable(result))
771
+ return result.then(null, errorFn);
772
+ return result;
773
+ }
774
+ catch (err) {
775
+ console.error(err);
776
+ }
777
+ }
778
+ function defineProp(obj, prop, getter, setter) {
779
+ Object.defineProperty(obj, prop, {
780
+ configurable: true,
781
+ enumerable: true,
782
+ get: getter,
783
+ set: setter,
784
+ });
785
+ }
786
+ function readonly(obj, prop, value = obj[prop]) {
787
+ defineProp(obj, prop, () => value, emptyFn);
788
+ }
789
+ function writable(obj, prop, value = obj[prop]) {
790
+ Object.defineProperty(obj, prop, {
791
+ configurable: true,
792
+ enumerable: true,
793
+ writable: true,
794
+ value: value,
795
+ });
796
+ }
797
+ function parseHeaders(obj) {
798
+ const headers = {};
799
+ switch (getType(obj)) {
800
+ case "[object String]":
801
+ for (const line of obj.trim().split(/[\r\n]+/)) {
802
+ const [header, value] = line.split(/(?<=^[^:]+)\s*:\s*/);
803
+ if (!value)
804
+ continue;
805
+ const lheader = header.toLowerCase();
806
+ headers[lheader] = lheader in headers ? `${headers[lheader]}, ${value}` : value;
807
+ }
808
+ break;
809
+ case "[object Headers]":
810
+ for (const [key, val] of obj) {
811
+ headers[key] = val;
812
+ }
813
+ break;
814
+ case "[object Object]":
815
+ return { ...obj };
816
+ }
817
+ return headers;
818
+ }
819
+ function stopImmediatePropagation() {
820
+ this.ajaxHooker_isStopped = true;
821
+ }
822
+ class SyncThenable {
823
+ then(fn) {
824
+ fn && fn();
825
+ return new SyncThenable();
826
+ }
827
+ }
828
+ class AHRequest {
829
+ constructor(request) {
830
+ this.request = request;
831
+ this.requestClone = { ...this.request };
832
+ }
833
+ _recoverRequestKey(key) {
834
+ if (key in this.requestClone)
835
+ this.request[key] = this.requestClone[key];
836
+ else
837
+ delete this.request[key];
838
+ }
839
+ shouldFilter(filters) {
840
+ const { type, url, method, async } = this.request;
841
+ return (filters.length &&
842
+ !filters.find((obj) => {
843
+ switch (true) {
844
+ case obj.type && obj.type !== type:
845
+ case getType(obj.url) === "[object String]" && !url.includes(obj.url):
846
+ case getType(obj.url) === "[object RegExp]" && !obj.url.test(url):
847
+ case obj.method && obj.method.toUpperCase() !== method.toUpperCase():
848
+ case "async" in obj && obj.async !== async:
849
+ return false;
850
+ }
851
+ return true;
852
+ }));
853
+ }
854
+ waitForRequestKeys() {
855
+ if (!this.request.async) {
856
+ win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
857
+ if (this.shouldFilter(filters))
858
+ return;
859
+ hookFns.forEach((fn) => {
860
+ if (getType(fn) === "[object Function]")
861
+ catchError(fn, this.request);
862
+ });
863
+ for (const key in this.request) {
864
+ if (isThenable(this.request[key]))
865
+ this._recoverRequestKey(key);
866
+ }
867
+ });
868
+ return new SyncThenable();
869
+ }
870
+ const promises = [];
871
+ const ignoreKeys = new Set(["type", "async", "response"]);
872
+ win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
873
+ if (this.shouldFilter(filters))
874
+ return;
875
+ promises.push(Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(() => {
876
+ const requestKeys = [];
877
+ for (const key in this.request)
878
+ !ignoreKeys.has(key) && requestKeys.push(key);
879
+ return Promise.all(requestKeys.map((key) => Promise.resolve(this.request[key]).then((val) => (this.request[key] = val), () => this._recoverRequestKey(key))));
880
+ }));
881
+ });
882
+ return Promise.all(promises);
883
+ }
884
+ waitForResponseKeys(response) {
885
+ const responseKeys = this.request.type === "xhr" ? xhrResponses : fetchResponses;
886
+ if (!this.request.async) {
887
+ if (getType(this.request.response) === "[object Function]") {
888
+ catchError(this.request.response, response);
889
+ responseKeys.forEach((key) => {
890
+ if ("get" in getDescriptor(response, key) || isThenable(response[key])) {
891
+ delete response[key];
892
+ }
893
+ });
894
+ }
895
+ return new SyncThenable();
896
+ }
897
+ return Promise.resolve(catchError(this.request.response, response)).then(() => Promise.all(responseKeys.map((key) => {
898
+ const descriptor = getDescriptor(response, key);
899
+ if (descriptor && "value" in descriptor) {
900
+ return Promise.resolve(descriptor.value).then((val) => (response[key] = val), () => delete response[key]);
901
+ }
902
+ else {
903
+ delete response[key];
904
+ }
905
+ })));
906
+ }
907
+ }
908
+ const proxyHandler = {
909
+ get(target, prop) {
910
+ const descriptor = getDescriptor(target, prop);
911
+ if (descriptor && !descriptor.configurable && !descriptor.writable && !descriptor.get)
912
+ return target[prop];
913
+ const ah = target.__ajaxHooker;
914
+ if (ah && ah.proxyProps) {
915
+ if (prop in ah.proxyProps) {
916
+ const pDescriptor = ah.proxyProps[prop];
917
+ if ("get" in pDescriptor)
918
+ return pDescriptor.get();
919
+ if (typeof pDescriptor.value === "function")
920
+ return pDescriptor.value.bind(ah);
921
+ return pDescriptor.value;
922
+ }
923
+ if (typeof target[prop] === "function")
924
+ return target[prop].bind(target);
925
+ }
926
+ return target[prop];
927
+ },
928
+ set(target, prop, value) {
929
+ const descriptor = getDescriptor(target, prop);
930
+ if (descriptor && !descriptor.configurable && !descriptor.writable && !descriptor.set)
931
+ return true;
932
+ const ah = target.__ajaxHooker;
933
+ if (ah && ah.proxyProps && prop in ah.proxyProps) {
934
+ const pDescriptor = ah.proxyProps[prop];
935
+ pDescriptor.set ? pDescriptor.set(value) : (pDescriptor.value = value);
936
+ }
937
+ else {
938
+ target[prop] = value;
939
+ }
940
+ return true;
941
+ },
942
+ };
943
+ class XhrHooker {
944
+ constructor(xhr) {
945
+ const ah = this;
946
+ Object.assign(ah, {
947
+ originalXhr: xhr,
948
+ proxyXhr: new Proxy(xhr, proxyHandler),
949
+ resThenable: new SyncThenable(),
950
+ proxyProps: {},
951
+ proxyEvents: {},
952
+ });
953
+ xhr.addEventListener("readystatechange", (e) => {
954
+ if (ah.proxyXhr.readyState === 4 && ah.request && typeof ah.request.response === "function") {
955
+ const response = {
956
+ finalUrl: ah.proxyXhr.responseURL,
957
+ status: ah.proxyXhr.status,
958
+ responseHeaders: parseHeaders(ah.proxyXhr.getAllResponseHeaders()),
959
+ };
960
+ const tempValues = {};
961
+ for (const key of xhrResponses) {
962
+ try {
963
+ tempValues[key] = ah.originalXhr[key];
964
+ }
965
+ catch (err) { }
966
+ defineProp(response, key, () => {
967
+ return (response[key] = tempValues[key]);
968
+ }, (val) => {
969
+ delete response[key];
970
+ response[key] = val;
971
+ });
972
+ }
973
+ ah.resThenable = new AHRequest(ah.request).waitForResponseKeys(response).then(() => {
974
+ for (const key of xhrResponses) {
975
+ ah.proxyProps[key] = {
976
+ get: () => {
977
+ if (!(key in response))
978
+ response[key] = tempValues[key];
979
+ return response[key];
980
+ },
981
+ };
982
+ }
983
+ });
984
+ }
985
+ ah.dispatchEvent(e);
986
+ });
987
+ xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
988
+ xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
989
+ for (const evt of xhrAsyncEvents) {
990
+ const onEvt = "on" + evt;
991
+ ah.proxyProps[onEvt] = {
992
+ get: () => ah.proxyEvents[onEvt] || null,
993
+ set: (val) => ah.addEvent(onEvt, val),
994
+ };
995
+ }
996
+ for (const method of ["setRequestHeader", "addEventListener", "removeEventListener", "open", "send"]) {
997
+ ah.proxyProps[method] = { value: ah[method] };
998
+ }
999
+ }
1000
+ toJSON() { } // Converting circular structure to JSON
1001
+ addEvent(type, event) {
1002
+ if (type.startsWith("on")) {
1003
+ this.proxyEvents[type] = typeof event === "function" ? event : null;
1004
+ }
1005
+ else {
1006
+ if (typeof event === "object" && event !== null)
1007
+ event = event.handleEvent;
1008
+ if (typeof event !== "function")
1009
+ return;
1010
+ this.proxyEvents[type] = this.proxyEvents[type] || new Set();
1011
+ this.proxyEvents[type].add(event);
1012
+ }
1013
+ }
1014
+ removeEvent(type, event) {
1015
+ if (type.startsWith("on")) {
1016
+ this.proxyEvents[type] = null;
1017
+ }
1018
+ else {
1019
+ if (typeof event === "object" && event !== null)
1020
+ event = event.handleEvent;
1021
+ this.proxyEvents[type] && this.proxyEvents[type].delete(event);
1022
+ }
1023
+ }
1024
+ dispatchEvent(e) {
1025
+ e.stopImmediatePropagation = stopImmediatePropagation;
1026
+ defineProp(e, "target", () => this.proxyXhr);
1027
+ defineProp(e, "currentTarget", () => this.proxyXhr);
1028
+ defineProp(e, "srcElement", () => this.proxyXhr);
1029
+ this.proxyEvents[e.type] &&
1030
+ this.proxyEvents[e.type].forEach((fn) => {
1031
+ this.resThenable.then(() => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e));
1032
+ });
1033
+ if (e.ajaxHooker_isStopped)
1034
+ return;
1035
+ const onEvent = this.proxyEvents["on" + e.type];
1036
+ onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
1037
+ }
1038
+ setRequestHeader(header, value) {
1039
+ this.originalXhr.setRequestHeader(header, value);
1040
+ if (!this.request)
1041
+ return;
1042
+ const headers = this.request.headers;
1043
+ headers[header] = header in headers ? `${headers[header]}, ${value}` : value;
1044
+ }
1045
+ addEventListener(...args) {
1046
+ if (xhrAsyncEvents.includes(args[0])) {
1047
+ this.addEvent(args[0], args[1]);
1048
+ }
1049
+ else {
1050
+ this.originalXhr.addEventListener(...args);
1051
+ }
1052
+ }
1053
+ removeEventListener(...args) {
1054
+ if (xhrAsyncEvents.includes(args[0])) {
1055
+ this.removeEvent(args[0], args[1]);
1056
+ }
1057
+ else {
1058
+ this.originalXhr.removeEventListener(...args);
1059
+ }
1060
+ }
1061
+ open(method, url, async = true, ...args) {
1062
+ this.request = {
1063
+ type: "xhr",
1064
+ url: url.toString(),
1065
+ method: method.toUpperCase(),
1066
+ abort: false,
1067
+ headers: {},
1068
+ data: null,
1069
+ response: null,
1070
+ async: !!async,
1071
+ };
1072
+ this.openArgs = args;
1073
+ this.resThenable = new SyncThenable();
1074
+ ["responseURL", "readyState", "status", "statusText", ...xhrResponses].forEach((key) => {
1075
+ delete this.proxyProps[key];
1076
+ });
1077
+ return this.originalXhr.open(method, url, async, ...args);
1078
+ }
1079
+ send(data) {
1080
+ const ah = this;
1081
+ const xhr = ah.originalXhr;
1082
+ const request = ah.request;
1083
+ if (!request)
1084
+ return xhr.send(data);
1085
+ request.data = data;
1086
+ new AHRequest(request).waitForRequestKeys().then(() => {
1087
+ if (request.abort) {
1088
+ if (typeof request.response === "function") {
1089
+ Object.assign(ah.proxyProps, {
1090
+ responseURL: { value: request.url },
1091
+ readyState: { value: 4 },
1092
+ status: { value: 200 },
1093
+ statusText: { value: "OK" },
1094
+ });
1095
+ xhrAsyncEvents.forEach((evt) => xhr.dispatchEvent(new Event(evt)));
1096
+ }
1097
+ }
1098
+ else {
1099
+ xhr.open(request.method, request.url, request.async, ...ah.openArgs);
1100
+ for (const header in request.headers) {
1101
+ xhr.setRequestHeader(header, request.headers[header]);
1102
+ }
1103
+ for (const prop of xhrExtraProps) {
1104
+ if (prop in request)
1105
+ xhr[prop] = request[prop];
1106
+ }
1107
+ xhr.send(request.data);
1108
+ }
1109
+ });
1110
+ }
1111
+ }
1112
+ function fakeXHR() {
1113
+ const xhr = new winAh.realXHR();
1114
+ if ("__ajaxHooker" in xhr)
1115
+ console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
1116
+ xhr.__ajaxHooker = new XhrHooker(xhr);
1117
+ return xhr.__ajaxHooker.proxyXhr;
1118
+ }
1119
+ fakeXHR.prototype = win.XMLHttpRequest.prototype;
1120
+ Object.keys(win.XMLHttpRequest).forEach((key) => (fakeXHR[key] = win.XMLHttpRequest[key]));
1121
+ function fakeFetch(url, options = {}) {
1122
+ if (!url)
1123
+ return winAh.realFetch.call(win, url, options);
1124
+ return new Promise(async (resolve, reject) => {
1125
+ const init = {};
1126
+ if (getType(url) === "[object Request]") {
1127
+ init.method = url.method;
1128
+ init.headers = url.headers;
1129
+ if (url.body)
1130
+ init.body = await url.arrayBuffer();
1131
+ for (const prop of fetchExtraProps)
1132
+ init[prop] = url[prop];
1133
+ url = url.url;
1134
+ }
1135
+ url = url.toString();
1136
+ Object.assign(init, options);
1137
+ init.method = init.method || "GET";
1138
+ init.headers = init.headers || {};
1139
+ const request = {
1140
+ type: "fetch",
1141
+ url: url,
1142
+ method: init.method.toUpperCase(),
1143
+ abort: false,
1144
+ headers: parseHeaders(init.headers),
1145
+ data: init.body,
1146
+ response: null,
1147
+ async: true,
1148
+ };
1149
+ const req = new AHRequest(request);
1150
+ await req.waitForRequestKeys();
1151
+ if (request.abort) {
1152
+ if (typeof request.response === "function") {
1153
+ const response = {
1154
+ finalUrl: request.url,
1155
+ status: 200,
1156
+ responseHeaders: {},
1157
+ };
1158
+ await req.waitForResponseKeys(response);
1159
+ const key = fetchResponses.find((k) => k in response);
1160
+ let val = response[key];
1161
+ if (key === "json" && typeof val === "object") {
1162
+ val = catchError(JSON.stringify.bind(JSON), val);
1163
+ }
1164
+ const res = new Response(val, {
1165
+ status: 200,
1166
+ statusText: "OK",
1167
+ });
1168
+ defineProp(res, "type", () => "basic");
1169
+ defineProp(res, "url", () => request.url);
1170
+ resolve(res);
1171
+ }
1172
+ else {
1173
+ reject(new DOMException("aborted", "AbortError"));
1174
+ }
1175
+ return;
1176
+ }
1177
+ init.method = request.method;
1178
+ init.headers = request.headers;
1179
+ init.body = request.data;
1180
+ for (const prop of fetchExtraProps) {
1181
+ if (prop in request)
1182
+ init[prop] = request[prop];
1183
+ }
1184
+ winAh.realFetch.call(win, request.url, init).then((res) => {
1185
+ if (typeof request.response === "function") {
1186
+ const response = {
1187
+ finalUrl: res.url,
1188
+ status: res.status,
1189
+ responseHeaders: parseHeaders(res.headers),
1190
+ };
1191
+ if (res.ok) {
1192
+ fetchResponses.forEach((key) => (res[key] = function () {
1193
+ if (key in response)
1194
+ return Promise.resolve(response[key]);
1195
+ return resProto[key].call(this).then((val) => {
1196
+ response[key] = val;
1197
+ return req
1198
+ .waitForResponseKeys(response)
1199
+ .then(() => (key in response ? response[key] : val));
1200
+ });
1201
+ }));
1202
+ }
1203
+ else {
1204
+ catchError(request.response, response);
1205
+ }
1206
+ }
1207
+ resolve(res);
1208
+ }, reject);
1209
+ });
1210
+ }
1211
+ function fakeFetchClone() {
1212
+ const descriptors = Object.getOwnPropertyDescriptors(this);
1213
+ const res = winAh.realFetchClone.call(this);
1214
+ Object.defineProperties(res, descriptors);
1215
+ return res;
1216
+ }
1217
+ winAh = win.__ajaxHooker = winAh || {
1218
+ version,
1219
+ fakeXHR,
1220
+ fakeFetch,
1221
+ fakeFetchClone,
1222
+ realXHR: win.XMLHttpRequest,
1223
+ realFetch: win.fetch,
1224
+ realFetchClone: resProto.clone,
1225
+ hookInsts: new Set(),
1226
+ };
1227
+ if (winAh.version !== version)
1228
+ console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
1229
+ win.XMLHttpRequest = winAh.fakeXHR;
1230
+ win.fetch = winAh.fakeFetch;
1231
+ resProto.clone = winAh.fakeFetchClone;
1232
+ winAh.hookInsts.add(hookInst);
1233
+ // 针对头条、抖音 secsdk.umd.js 的兼容性处理
1234
+ class AHFunction extends Function {
1235
+ call(thisArg, ...args) {
1236
+ if (thisArg && thisArg.__ajaxHooker && thisArg.__ajaxHooker.proxyXhr === thisArg) {
1237
+ thisArg = thisArg.__ajaxHooker.originalXhr;
1238
+ }
1239
+ return Reflect.apply(this, thisArg, args);
1240
+ }
1241
+ apply(thisArg, args) {
1242
+ if (thisArg && thisArg.__ajaxHooker && thisArg.__ajaxHooker.proxyXhr === thisArg) {
1243
+ thisArg = thisArg.__ajaxHooker.originalXhr;
1244
+ }
1245
+ return Reflect.apply(this, thisArg, args || []);
1246
+ }
1247
+ }
1248
+ function hookSecsdk(csrf) {
1249
+ Object.setPrototypeOf(csrf.nativeXMLHttpRequestSetRequestHeader, AHFunction.prototype);
1250
+ Object.setPrototypeOf(csrf.nativeXMLHttpRequestOpen, AHFunction.prototype);
1251
+ Object.setPrototypeOf(csrf.nativeXMLHttpRequestSend, AHFunction.prototype);
1252
+ }
1253
+ if (win.secsdk) {
1254
+ if (win.secsdk.csrf && win.secsdk.csrf.nativeXMLHttpRequestOpen)
1255
+ hookSecsdk(win.secsdk.csrf);
1256
+ }
1257
+ else {
1258
+ defineProp(win, "secsdk", emptyFn, (secsdk) => {
1259
+ delete win.secsdk;
1260
+ win.secsdk = secsdk;
1261
+ defineProp(secsdk, "csrf", emptyFn, (csrf) => {
1262
+ delete secsdk.csrf;
1263
+ secsdk.csrf = csrf;
1264
+ if (csrf.nativeXMLHttpRequestOpen)
1265
+ hookSecsdk(csrf);
1266
+ });
1267
+ });
1268
+ }
1269
+ return {
1270
+ hook: (fn) => hookInst.hookFns.push(fn),
1271
+ filter: (arr) => {
1272
+ if (Array.isArray(arr))
1273
+ hookInst.filters = arr;
1274
+ },
1275
+ protect: () => {
1276
+ readonly(win, "XMLHttpRequest", winAh.fakeXHR);
1277
+ readonly(win, "fetch", winAh.fakeFetch);
1278
+ readonly(resProto, "clone", winAh.fakeFetchClone);
1279
+ },
1280
+ unhook: () => {
1281
+ winAh.hookInsts.delete(hookInst);
1282
+ if (!winAh.hookInsts.size) {
1283
+ writable(win, "XMLHttpRequest", winAh.realXHR);
1284
+ writable(win, "fetch", winAh.realFetch);
1285
+ writable(resProto, "clone", winAh.realFetchClone);
1286
+ delete win.__ajaxHooker;
1287
+ }
1288
+ },
1289
+ };
1267
1290
  };
1268
1291
 
1269
- // ==UserScript==
1270
- // @name ajaxHooker
1271
- // @author cxxjackie
1272
- // @version 1.2.4
1273
- // @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
1274
- // ==/UserScript==
1275
-
1276
- const AjaxHooker1_2_4 = function () {
1277
- return (function () {
1278
- const win = window.unsafeWindow || document.defaultView || window;
1279
- const hookFns = [];
1280
- const realXhr = win.XMLHttpRequest;
1281
- const resProto = win.Response.prototype;
1282
- const toString = Object.prototype.toString;
1283
- const realFetch = win.fetch;
1284
- const xhrResponses = ["response", "responseText", "responseXML"];
1285
- const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
1286
- const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
1287
- let filter;
1288
- function emptyFn() {}
1289
- function errorFn(err) {
1290
- console.error(err);
1291
- }
1292
- function defineProp(obj, prop, getter, setter) {
1293
- Object.defineProperty(obj, prop, {
1294
- configurable: true,
1295
- enumerable: true,
1296
- get: getter,
1297
- set: setter,
1298
- });
1299
- }
1300
- function readonly(obj, prop, value = obj[prop]) {
1301
- defineProp(obj, prop, () => value, emptyFn);
1302
- }
1303
- function writable(obj, prop, value = obj[prop]) {
1304
- Object.defineProperty(obj, prop, {
1305
- configurable: true,
1306
- enumerable: true,
1307
- writable: true,
1308
- value: value,
1309
- });
1310
- }
1311
- function toFilterObj(obj) {
1312
- return {
1313
- type: obj.type,
1314
- url: obj.url,
1315
- method: obj.method && obj.method.toUpperCase(),
1316
- };
1317
- }
1318
- function shouldFilter(type, url, method) {
1319
- return (
1320
- filter &&
1321
- !filter.find(
1322
- (obj) =>
1323
- (!obj.type || obj.type === type) &&
1324
- (!obj.url ||
1325
- (toString.call(obj.url) === "[object String]"
1326
- ? url.includes(obj.url)
1327
- : obj.url.test(url))) &&
1328
- (!obj.method || obj.method === method.toUpperCase())
1329
- )
1330
- );
1331
- }
1332
- function lookupGetter(obj, prop) {
1333
- let getter;
1334
- let proto = obj;
1335
- while (proto) {
1336
- const descriptor = Object.getOwnPropertyDescriptor(proto, prop);
1337
- getter = descriptor && descriptor.get;
1338
- if (getter) break;
1339
- proto = Object.getPrototypeOf(proto);
1340
- }
1341
- return getter ? getter.bind(obj) : emptyFn;
1342
- }
1343
- function waitForHookFns(request) {
1344
- return Promise.all(
1345
- hookFns.map((fn) => Promise.resolve(fn(request)).then(emptyFn, errorFn))
1346
- );
1347
- }
1348
- function waitForRequestKeys(request, requestClone) {
1349
- return Promise.all(
1350
- ["url", "method", "abort", "headers", "data"].map((key) => {
1351
- return Promise.resolve(request[key]).then(
1352
- (val) => (request[key] = val),
1353
- () => (request[key] = requestClone[key])
1354
- );
1355
- })
1356
- );
1357
- }
1358
- function fakeEventSIP() {
1359
- this.ajaxHooker_stopped = true;
1360
- }
1361
- function xhrDelegateEvent(e) {
1362
- const xhr = e.target;
1363
- e.stopImmediatePropagation = fakeEventSIP;
1364
- xhr.__ajaxHooker.hookedEvents[e.type].forEach(
1365
- (fn) => !e.ajaxHooker_stopped && fn.call(xhr, e)
1366
- );
1367
- const onEvent = xhr.__ajaxHooker.hookedEvents["on" + e.type];
1368
- typeof onEvent === "function" && onEvent.call(xhr, e);
1369
- }
1370
- function xhrReadyStateChange(e) {
1371
- if (e.target.readyState === 4) {
1372
- e.target.dispatchEvent(
1373
- new CustomEvent("ajaxHooker_responseReady", { detail: e })
1374
- );
1375
- } else {
1376
- e.target.__ajaxHooker.delegateEvent(e);
1377
- }
1378
- }
1379
- function xhrLoadAndLoadend(e) {
1380
- e.target.__ajaxHooker.delegateEvent(e);
1381
- }
1382
- function fakeXhrOpen(method, url, ...args) {
1383
- const ah = this.__ajaxHooker;
1384
- ah.url = url.toString();
1385
- ah.method = method.toUpperCase();
1386
- ah.openArgs = args;
1387
- ah.headers = {};
1388
- return ah.originalMethods.open(method, url, ...args);
1389
- }
1390
- function fakeXhr() {
1391
- const xhr = new realXhr();
1392
- let ah = xhr.__ajaxHooker;
1393
- if (!ah) {
1394
- ah = xhr.__ajaxHooker = {
1395
- headers: {},
1396
- hookedEvents: {
1397
- readystatechange: new Set(),
1398
- load: new Set(),
1399
- loadend: new Set(),
1400
- },
1401
- delegateEvent: xhrDelegateEvent,
1402
- originalGetters: {},
1403
- originalMethods: {},
1404
- };
1405
- xhr.addEventListener("readystatechange", xhrReadyStateChange);
1406
- xhr.addEventListener("load", xhrLoadAndLoadend);
1407
- xhr.addEventListener("loadend", xhrLoadAndLoadend);
1408
- for (const key of xhrResponses) {
1409
- ah.originalGetters[key] = lookupGetter(xhr, key);
1410
- }
1411
- for (const method of [
1412
- "open",
1413
- "setRequestHeader",
1414
- "addEventListener",
1415
- "removeEventListener",
1416
- ]) {
1417
- ah.originalMethods[method] = xhr[method].bind(xhr);
1418
- }
1419
- xhr.open = fakeXhrOpen;
1420
- xhr.setRequestHeader = (header, value) => {
1421
- ah.originalMethods.setRequestHeader(header, value);
1422
- if (xhr.readyState === 1) {
1423
- if (ah.headers[header]) {
1424
- ah.headers[header] += ", " + value;
1425
- } else {
1426
- ah.headers[header] = value;
1427
- }
1428
- }
1429
- };
1430
- xhr.addEventListener = function (...args) {
1431
- if (xhrAsyncEvents.includes(args[0])) {
1432
- ah.hookedEvents[args[0]].add(args[1]);
1433
- } else {
1434
- ah.originalMethods.addEventListener(...args);
1435
- }
1436
- };
1437
- xhr.removeEventListener = function (...args) {
1438
- if (xhrAsyncEvents.includes(args[0])) {
1439
- ah.hookedEvents[args[0]].delete(args[1]);
1440
- } else {
1441
- ah.originalMethods.removeEventListener(...args);
1442
- }
1443
- };
1444
- xhrAsyncEvents.forEach((evt) => {
1445
- const onEvt = "on" + evt;
1446
- defineProp(
1447
- xhr,
1448
- onEvt,
1449
- () => {
1450
- return ah.hookedEvents[onEvt] || null;
1451
- },
1452
- (val) => {
1453
- ah.hookedEvents[onEvt] = typeof val === "function" ? val : null;
1454
- }
1455
- );
1456
- });
1457
- }
1458
- const realSend = xhr.send.bind(xhr);
1459
- xhr.send = function (data) {
1460
- if (xhr.readyState !== 1) return realSend(data);
1461
- ah.delegateEvent = xhrDelegateEvent;
1462
- xhrResponses.forEach((prop) => {
1463
- delete xhr[prop]; // delete descriptor
1464
- });
1465
- if (shouldFilter("xhr", ah.url, ah.method)) {
1466
- xhr.addEventListener("ajaxHooker_responseReady", (e) => {
1467
- ah.delegateEvent(e.detail);
1468
- });
1469
- return realSend(data);
1470
- }
1471
- try {
1472
- const request = {
1473
- type: "xhr",
1474
- url: ah.url,
1475
- method: ah.method,
1476
- abort: false,
1477
- headers: ah.headers,
1478
- data: data,
1479
- response: null,
1480
- };
1481
- const requestClone = { ...request };
1482
- waitForHookFns(request).then(() => {
1483
- waitForRequestKeys(request, requestClone).then(() => {
1484
- if (request.abort) return;
1485
- ah.originalMethods.open(
1486
- request.method,
1487
- request.url,
1488
- ...ah.openArgs
1489
- );
1490
- for (const header in request.headers) {
1491
- ah.originalMethods.setRequestHeader(
1492
- header,
1493
- request.headers[header]
1494
- );
1495
- }
1496
- data = request.data;
1497
- xhr.addEventListener("ajaxHooker_responseReady", (e) => {
1498
- try {
1499
- if (typeof request.response === "function") {
1500
- const arg = {
1501
- finalUrl: xhr.responseURL,
1502
- status: xhr.status,
1503
- responseHeaders: {},
1504
- };
1505
- for (const line of xhr
1506
- .getAllResponseHeaders()
1507
- .trim()
1508
- .split(/[\r\n]+/)) {
1509
- const parts = line.split(/:\s*/);
1510
- if (parts.length === 2) {
1511
- const lheader = parts[0].toLowerCase();
1512
- if (arg.responseHeaders[lheader]) {
1513
- arg.responseHeaders[lheader] += ", " + parts[1];
1514
- } else {
1515
- arg.responseHeaders[lheader] = parts[1];
1516
- }
1517
- }
1518
- }
1519
- xhrResponses.forEach((prop) => {
1520
- defineProp(
1521
- arg,
1522
- prop,
1523
- () => {
1524
- return (arg[prop] = ah.originalGetters[prop]());
1525
- },
1526
- (val) => {
1527
- delete arg[prop];
1528
- arg[prop] = val;
1529
- }
1530
- );
1531
- defineProp(xhr, prop, () => {
1532
- const val = ah.originalGetters[prop]();
1533
- xhr.dispatchEvent(
1534
- new CustomEvent("ajaxHooker_readResponse", {
1535
- detail: { prop, val },
1536
- })
1537
- );
1538
- return val;
1539
- });
1540
- });
1541
- xhr.addEventListener("ajaxHooker_readResponse", (e) => {
1542
- arg[e.detail.prop] = e.detail.val;
1543
- });
1544
- const resPromise = Promise.resolve(
1545
- request.response(arg)
1546
- ).then(() => {
1547
- const task = [];
1548
- xhrResponses.forEach((prop) => {
1549
- const descriptor = Object.getOwnPropertyDescriptor(
1550
- arg,
1551
- prop
1552
- );
1553
- if (descriptor && "value" in descriptor) {
1554
- task.push(
1555
- Promise.resolve(descriptor.value).then((val) => {
1556
- arg[prop] = val;
1557
- defineProp(xhr, prop, () => {
1558
- xhr.dispatchEvent(
1559
- new CustomEvent("ajaxHooker_readResponse", {
1560
- detail: { prop, val },
1561
- })
1562
- );
1563
- return val;
1564
- });
1565
- }, emptyFn)
1566
- );
1567
- }
1568
- });
1569
- return Promise.all(task);
1570
- }, errorFn);
1571
- const eventsClone = {};
1572
- xhrAsyncEvents.forEach((type) => {
1573
- eventsClone[type] = new Set([...ah.hookedEvents[type]]);
1574
- eventsClone["on" + type] = ah.hookedEvents["on" + type];
1575
- });
1576
- ah.delegateEvent = (event) =>
1577
- resPromise.then(() => {
1578
- event.stopImmediatePropagation = fakeEventSIP;
1579
- eventsClone[event.type].forEach(
1580
- (fn) =>
1581
- !event.ajaxHooker_stopped && fn.call(xhr, event)
1582
- );
1583
- const onEvent = eventsClone["on" + event.type];
1584
- typeof onEvent === "function" &&
1585
- onEvent.call(xhr, event);
1586
- });
1587
- }
1588
- } catch (err) {
1589
- console.error(err);
1590
- }
1591
- ah.delegateEvent(e.detail);
1592
- });
1593
- realSend(data);
1594
- });
1595
- });
1596
- } catch (err) {
1597
- console.error(err);
1598
- realSend(data);
1599
- }
1600
- };
1601
- return xhr;
1602
- }
1603
- function hookFetchResponse(response, arg, callback) {
1604
- fetchResponses.forEach((prop) => {
1605
- response[prop] = () =>
1606
- new Promise((resolve, reject) => {
1607
- resProto[prop].call(response).then((res) => {
1608
- if (prop in arg) {
1609
- resolve(arg[prop]);
1610
- } else {
1611
- try {
1612
- arg[prop] = res;
1613
- Promise.resolve(callback(arg)).then(() => {
1614
- if (prop in arg) {
1615
- Promise.resolve(arg[prop]).then(
1616
- (val) => resolve((arg[prop] = val)),
1617
- () => resolve(res)
1618
- );
1619
- } else {
1620
- resolve(res);
1621
- }
1622
- }, errorFn);
1623
- } catch (err) {
1624
- console.error(err);
1625
- resolve(res);
1626
- }
1627
- }
1628
- }, reject);
1629
- });
1630
- });
1631
- }
1632
- function fakeFetch(url, init) {
1633
- if (url && typeof url.toString === "function") {
1634
- url = url.toString();
1635
- init = init || {};
1636
- init.method = init.method || "GET";
1637
- init.headers = init.headers || {};
1638
- if (shouldFilter("fetch", url, init.method))
1639
- return realFetch.call(win, url, init);
1640
- const request = {
1641
- type: "fetch",
1642
- url: url,
1643
- method: init.method.toUpperCase(),
1644
- abort: false,
1645
- headers: {},
1646
- data: init.body,
1647
- response: null,
1648
- };
1649
- if (toString.call(init.headers) === "[object Headers]") {
1650
- for (const [key, val] of init.headers) {
1651
- request.headers[key] = val;
1652
- }
1653
- } else {
1654
- request.headers = { ...init.headers };
1655
- }
1656
- const requestClone = { ...request };
1657
- return new Promise((resolve, reject) => {
1658
- try {
1659
- waitForHookFns(request).then(() => {
1660
- waitForRequestKeys(request, requestClone).then(() => {
1661
- if (request.abort) return reject("aborted");
1662
- url = request.url;
1663
- init.method = request.method;
1664
- init.headers = request.headers;
1665
- init.body = request.data;
1666
- realFetch.call(win, url, init).then((response) => {
1667
- if (typeof request.response === "function") {
1668
- const arg = {
1669
- finalUrl: response.url,
1670
- status: response.status,
1671
- responseHeaders: {},
1672
- };
1673
- for (const [key, val] of response.headers) {
1674
- arg.responseHeaders[key] = val;
1675
- }
1676
- hookFetchResponse(response, arg, request.response);
1677
- response.clone = () => {
1678
- const resClone = resProto.clone.call(response);
1679
- hookFetchResponse(resClone, arg, request.response);
1680
- return resClone;
1681
- };
1682
- }
1683
- resolve(response);
1684
- }, reject);
1685
- });
1686
- });
1687
- } catch (err) {
1688
- console.error(err);
1689
- return realFetch.call(win, url, init);
1690
- }
1691
- });
1692
- } else {
1693
- return realFetch.call(win, url, init);
1694
- }
1695
- }
1696
- win.XMLHttpRequest = fakeXhr;
1697
- Object.keys(realXhr).forEach((key) => (fakeXhr[key] = realXhr[key]));
1698
- fakeXhr.prototype = realXhr.prototype;
1699
- win.fetch = fakeFetch;
1700
- return {
1701
- hook: (fn) => hookFns.push(fn),
1702
- filter: (arr) => {
1703
- filter = Array.isArray(arr) && arr.map(toFilterObj);
1704
- },
1705
- protect: () => {
1706
- readonly(win, "XMLHttpRequest", fakeXhr);
1707
- readonly(win, "fetch", fakeFetch);
1708
- },
1709
- unhook: () => {
1710
- writable(win, "XMLHttpRequest", realXhr);
1711
- writable(win, "fetch", realFetch);
1712
- },
1713
- };
1714
- })();
1292
+ // ==UserScript==
1293
+ // @name ajaxHooker
1294
+ // @author cxxjackie
1295
+ // @version 1.2.4
1296
+ // @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
1297
+ // ==/UserScript==
1298
+ const AjaxHooker1_2_4 = function () {
1299
+ return (function () {
1300
+ const win = window.unsafeWindow || document.defaultView || window;
1301
+ const hookFns = [];
1302
+ const realXhr = win.XMLHttpRequest;
1303
+ const resProto = win.Response.prototype;
1304
+ const toString = Object.prototype.toString;
1305
+ const realFetch = win.fetch;
1306
+ const xhrResponses = ["response", "responseText", "responseXML"];
1307
+ const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
1308
+ const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
1309
+ let filter;
1310
+ function emptyFn() { }
1311
+ function errorFn(err) {
1312
+ console.error(err);
1313
+ }
1314
+ function defineProp(obj, prop, getter, setter) {
1315
+ Object.defineProperty(obj, prop, {
1316
+ configurable: true,
1317
+ enumerable: true,
1318
+ get: getter,
1319
+ set: setter,
1320
+ });
1321
+ }
1322
+ function readonly(obj, prop, value = obj[prop]) {
1323
+ defineProp(obj, prop, () => value, emptyFn);
1324
+ }
1325
+ function writable(obj, prop, value = obj[prop]) {
1326
+ Object.defineProperty(obj, prop, {
1327
+ configurable: true,
1328
+ enumerable: true,
1329
+ writable: true,
1330
+ value: value,
1331
+ });
1332
+ }
1333
+ function toFilterObj(obj) {
1334
+ return {
1335
+ type: obj.type,
1336
+ url: obj.url,
1337
+ method: obj.method && obj.method.toUpperCase(),
1338
+ };
1339
+ }
1340
+ function shouldFilter(type, url, method) {
1341
+ return (filter &&
1342
+ !filter.find((obj) => (!obj.type || obj.type === type) &&
1343
+ (!obj.url ||
1344
+ (toString.call(obj.url) === "[object String]"
1345
+ ? url.includes(obj.url)
1346
+ : obj.url.test(url))) &&
1347
+ (!obj.method || obj.method === method.toUpperCase())));
1348
+ }
1349
+ function lookupGetter(obj, prop) {
1350
+ let getter;
1351
+ let proto = obj;
1352
+ while (proto) {
1353
+ const descriptor = Object.getOwnPropertyDescriptor(proto, prop);
1354
+ getter = descriptor && descriptor.get;
1355
+ if (getter)
1356
+ break;
1357
+ proto = Object.getPrototypeOf(proto);
1358
+ }
1359
+ return getter ? getter.bind(obj) : emptyFn;
1360
+ }
1361
+ function waitForHookFns(request) {
1362
+ return Promise.all(hookFns.map((fn) => Promise.resolve(fn(request)).then(emptyFn, errorFn)));
1363
+ }
1364
+ function waitForRequestKeys(request, requestClone) {
1365
+ return Promise.all(["url", "method", "abort", "headers", "data"].map((key) => {
1366
+ return Promise.resolve(request[key]).then((val) => (request[key] = val), () => (request[key] = requestClone[key]));
1367
+ }));
1368
+ }
1369
+ function fakeEventSIP() {
1370
+ this.ajaxHooker_stopped = true;
1371
+ }
1372
+ function xhrDelegateEvent(e) {
1373
+ const xhr = e.target;
1374
+ e.stopImmediatePropagation = fakeEventSIP;
1375
+ xhr.__ajaxHooker.hookedEvents[e.type].forEach((fn) => !e.ajaxHooker_stopped && fn.call(xhr, e));
1376
+ const onEvent = xhr.__ajaxHooker.hookedEvents["on" + e.type];
1377
+ typeof onEvent === "function" && onEvent.call(xhr, e);
1378
+ }
1379
+ function xhrReadyStateChange(e) {
1380
+ if (e.target.readyState === 4) {
1381
+ e.target.dispatchEvent(new CustomEvent("ajaxHooker_responseReady", { detail: e }));
1382
+ }
1383
+ else {
1384
+ e.target.__ajaxHooker.delegateEvent(e);
1385
+ }
1386
+ }
1387
+ function xhrLoadAndLoadend(e) {
1388
+ e.target.__ajaxHooker.delegateEvent(e);
1389
+ }
1390
+ function fakeXhrOpen(method, url, ...args) {
1391
+ const ah = this.__ajaxHooker;
1392
+ ah.url = url.toString();
1393
+ ah.method = method.toUpperCase();
1394
+ ah.openArgs = args;
1395
+ ah.headers = {};
1396
+ return ah.originalMethods.open(method, url, ...args);
1397
+ }
1398
+ function fakeXhr() {
1399
+ const xhr = new realXhr();
1400
+ let ah = xhr.__ajaxHooker;
1401
+ if (!ah) {
1402
+ ah = xhr.__ajaxHooker = {
1403
+ headers: {},
1404
+ hookedEvents: {
1405
+ readystatechange: new Set(),
1406
+ load: new Set(),
1407
+ loadend: new Set(),
1408
+ },
1409
+ delegateEvent: xhrDelegateEvent,
1410
+ originalGetters: {},
1411
+ originalMethods: {},
1412
+ };
1413
+ xhr.addEventListener("readystatechange", xhrReadyStateChange);
1414
+ xhr.addEventListener("load", xhrLoadAndLoadend);
1415
+ xhr.addEventListener("loadend", xhrLoadAndLoadend);
1416
+ for (const key of xhrResponses) {
1417
+ ah.originalGetters[key] = lookupGetter(xhr, key);
1418
+ }
1419
+ for (const method of [
1420
+ "open",
1421
+ "setRequestHeader",
1422
+ "addEventListener",
1423
+ "removeEventListener",
1424
+ ]) {
1425
+ ah.originalMethods[method] = xhr[method].bind(xhr);
1426
+ }
1427
+ xhr.open = fakeXhrOpen;
1428
+ xhr.setRequestHeader = (header, value) => {
1429
+ ah.originalMethods.setRequestHeader(header, value);
1430
+ if (xhr.readyState === 1) {
1431
+ if (ah.headers[header]) {
1432
+ ah.headers[header] += ", " + value;
1433
+ }
1434
+ else {
1435
+ ah.headers[header] = value;
1436
+ }
1437
+ }
1438
+ };
1439
+ xhr.addEventListener = function (...args) {
1440
+ if (xhrAsyncEvents.includes(args[0])) {
1441
+ ah.hookedEvents[args[0]].add(args[1]);
1442
+ }
1443
+ else {
1444
+ ah.originalMethods.addEventListener(...args);
1445
+ }
1446
+ };
1447
+ xhr.removeEventListener = function (...args) {
1448
+ if (xhrAsyncEvents.includes(args[0])) {
1449
+ ah.hookedEvents[args[0]].delete(args[1]);
1450
+ }
1451
+ else {
1452
+ ah.originalMethods.removeEventListener(...args);
1453
+ }
1454
+ };
1455
+ xhrAsyncEvents.forEach((evt) => {
1456
+ const onEvt = "on" + evt;
1457
+ defineProp(xhr, onEvt, () => {
1458
+ return ah.hookedEvents[onEvt] || null;
1459
+ }, (val) => {
1460
+ ah.hookedEvents[onEvt] = typeof val === "function" ? val : null;
1461
+ });
1462
+ });
1463
+ }
1464
+ const realSend = xhr.send.bind(xhr);
1465
+ xhr.send = function (data) {
1466
+ if (xhr.readyState !== 1)
1467
+ return realSend(data);
1468
+ ah.delegateEvent = xhrDelegateEvent;
1469
+ xhrResponses.forEach((prop) => {
1470
+ delete xhr[prop]; // delete descriptor
1471
+ });
1472
+ if (shouldFilter("xhr", ah.url, ah.method)) {
1473
+ xhr.addEventListener("ajaxHooker_responseReady", (e) => {
1474
+ ah.delegateEvent(e.detail);
1475
+ });
1476
+ return realSend(data);
1477
+ }
1478
+ try {
1479
+ const request = {
1480
+ type: "xhr",
1481
+ url: ah.url,
1482
+ method: ah.method,
1483
+ abort: false,
1484
+ headers: ah.headers,
1485
+ data: data,
1486
+ response: null,
1487
+ };
1488
+ const requestClone = { ...request };
1489
+ waitForHookFns(request).then(() => {
1490
+ waitForRequestKeys(request, requestClone).then(() => {
1491
+ if (request.abort)
1492
+ return;
1493
+ ah.originalMethods.open(request.method, request.url, ...ah.openArgs);
1494
+ for (const header in request.headers) {
1495
+ ah.originalMethods.setRequestHeader(header, request.headers[header]);
1496
+ }
1497
+ data = request.data;
1498
+ xhr.addEventListener("ajaxHooker_responseReady", (e) => {
1499
+ try {
1500
+ if (typeof request.response === "function") {
1501
+ const arg = {
1502
+ finalUrl: xhr.responseURL,
1503
+ status: xhr.status,
1504
+ responseHeaders: {},
1505
+ };
1506
+ for (const line of xhr
1507
+ .getAllResponseHeaders()
1508
+ .trim()
1509
+ .split(/[\r\n]+/)) {
1510
+ const parts = line.split(/:\s*/);
1511
+ if (parts.length === 2) {
1512
+ const lheader = parts[0].toLowerCase();
1513
+ if (arg.responseHeaders[lheader]) {
1514
+ arg.responseHeaders[lheader] += ", " + parts[1];
1515
+ }
1516
+ else {
1517
+ arg.responseHeaders[lheader] = parts[1];
1518
+ }
1519
+ }
1520
+ }
1521
+ xhrResponses.forEach((prop) => {
1522
+ defineProp(arg, prop, () => {
1523
+ return (arg[prop] = ah.originalGetters[prop]());
1524
+ }, (val) => {
1525
+ delete arg[prop];
1526
+ arg[prop] = val;
1527
+ });
1528
+ defineProp(xhr, prop, () => {
1529
+ const val = ah.originalGetters[prop]();
1530
+ xhr.dispatchEvent(new CustomEvent("ajaxHooker_readResponse", {
1531
+ detail: { prop, val },
1532
+ }));
1533
+ return val;
1534
+ });
1535
+ });
1536
+ xhr.addEventListener("ajaxHooker_readResponse", (e) => {
1537
+ arg[e.detail.prop] = e.detail.val;
1538
+ });
1539
+ const resPromise = Promise.resolve(request.response(arg)).then(() => {
1540
+ const task = [];
1541
+ xhrResponses.forEach((prop) => {
1542
+ const descriptor = Object.getOwnPropertyDescriptor(arg, prop);
1543
+ if (descriptor && "value" in descriptor) {
1544
+ task.push(Promise.resolve(descriptor.value).then((val) => {
1545
+ arg[prop] = val;
1546
+ defineProp(xhr, prop, () => {
1547
+ xhr.dispatchEvent(new CustomEvent("ajaxHooker_readResponse", {
1548
+ detail: { prop, val },
1549
+ }));
1550
+ return val;
1551
+ });
1552
+ }, emptyFn));
1553
+ }
1554
+ });
1555
+ return Promise.all(task);
1556
+ }, errorFn);
1557
+ const eventsClone = {};
1558
+ xhrAsyncEvents.forEach((type) => {
1559
+ eventsClone[type] = new Set([...ah.hookedEvents[type]]);
1560
+ eventsClone["on" + type] = ah.hookedEvents["on" + type];
1561
+ });
1562
+ ah.delegateEvent = (event) => resPromise.then(() => {
1563
+ event.stopImmediatePropagation = fakeEventSIP;
1564
+ eventsClone[event.type].forEach((fn) => !event.ajaxHooker_stopped && fn.call(xhr, event));
1565
+ const onEvent = eventsClone["on" + event.type];
1566
+ typeof onEvent === "function" &&
1567
+ onEvent.call(xhr, event);
1568
+ });
1569
+ }
1570
+ }
1571
+ catch (err) {
1572
+ console.error(err);
1573
+ }
1574
+ ah.delegateEvent(e.detail);
1575
+ });
1576
+ realSend(data);
1577
+ });
1578
+ });
1579
+ }
1580
+ catch (err) {
1581
+ console.error(err);
1582
+ realSend(data);
1583
+ }
1584
+ };
1585
+ return xhr;
1586
+ }
1587
+ function hookFetchResponse(response, arg, callback) {
1588
+ fetchResponses.forEach((prop) => {
1589
+ response[prop] = () => new Promise((resolve, reject) => {
1590
+ resProto[prop].call(response).then((res) => {
1591
+ if (prop in arg) {
1592
+ resolve(arg[prop]);
1593
+ }
1594
+ else {
1595
+ try {
1596
+ arg[prop] = res;
1597
+ Promise.resolve(callback(arg)).then(() => {
1598
+ if (prop in arg) {
1599
+ Promise.resolve(arg[prop]).then((val) => resolve((arg[prop] = val)), () => resolve(res));
1600
+ }
1601
+ else {
1602
+ resolve(res);
1603
+ }
1604
+ }, errorFn);
1605
+ }
1606
+ catch (err) {
1607
+ console.error(err);
1608
+ resolve(res);
1609
+ }
1610
+ }
1611
+ }, reject);
1612
+ });
1613
+ });
1614
+ }
1615
+ function fakeFetch(url, init) {
1616
+ if (url && typeof url.toString === "function") {
1617
+ url = url.toString();
1618
+ init = init || {};
1619
+ init.method = init.method || "GET";
1620
+ init.headers = init.headers || {};
1621
+ if (shouldFilter("fetch", url, init.method))
1622
+ return realFetch.call(win, url, init);
1623
+ const request = {
1624
+ type: "fetch",
1625
+ url: url,
1626
+ method: init.method.toUpperCase(),
1627
+ abort: false,
1628
+ headers: {},
1629
+ data: init.body,
1630
+ response: null,
1631
+ };
1632
+ if (toString.call(init.headers) === "[object Headers]") {
1633
+ for (const [key, val] of init.headers) {
1634
+ request.headers[key] = val;
1635
+ }
1636
+ }
1637
+ else {
1638
+ request.headers = { ...init.headers };
1639
+ }
1640
+ const requestClone = { ...request };
1641
+ return new Promise((resolve, reject) => {
1642
+ try {
1643
+ waitForHookFns(request).then(() => {
1644
+ waitForRequestKeys(request, requestClone).then(() => {
1645
+ if (request.abort)
1646
+ return reject("aborted");
1647
+ url = request.url;
1648
+ init.method = request.method;
1649
+ init.headers = request.headers;
1650
+ init.body = request.data;
1651
+ realFetch.call(win, url, init).then((response) => {
1652
+ if (typeof request.response === "function") {
1653
+ const arg = {
1654
+ finalUrl: response.url,
1655
+ status: response.status,
1656
+ responseHeaders: {},
1657
+ };
1658
+ for (const [key, val] of response.headers) {
1659
+ arg.responseHeaders[key] = val;
1660
+ }
1661
+ hookFetchResponse(response, arg, request.response);
1662
+ response.clone = () => {
1663
+ const resClone = resProto.clone.call(response);
1664
+ hookFetchResponse(resClone, arg, request.response);
1665
+ return resClone;
1666
+ };
1667
+ }
1668
+ resolve(response);
1669
+ }, reject);
1670
+ });
1671
+ });
1672
+ }
1673
+ catch (err) {
1674
+ console.error(err);
1675
+ return realFetch.call(win, url, init);
1676
+ }
1677
+ });
1678
+ }
1679
+ else {
1680
+ return realFetch.call(win, url, init);
1681
+ }
1682
+ }
1683
+ win.XMLHttpRequest = fakeXhr;
1684
+ Object.keys(realXhr).forEach((key) => (fakeXhr[key] = realXhr[key]));
1685
+ fakeXhr.prototype = realXhr.prototype;
1686
+ win.fetch = fakeFetch;
1687
+ return {
1688
+ hook: (fn) => hookFns.push(fn),
1689
+ filter: (arr) => {
1690
+ filter = Array.isArray(arr) && arr.map(toFilterObj);
1691
+ },
1692
+ protect: () => {
1693
+ readonly(win, "XMLHttpRequest", fakeXhr);
1694
+ readonly(win, "fetch", fakeFetch);
1695
+ },
1696
+ unhook: () => {
1697
+ writable(win, "XMLHttpRequest", realXhr);
1698
+ writable(win, "fetch", realFetch);
1699
+ },
1700
+ };
1701
+ })();
1715
1702
  };
1716
1703
 
1717
1704
  class GMMenu {
@@ -4217,9 +4204,35 @@
4217
4204
 
4218
4205
  class UtilsDictionary {
4219
4206
  items;
4220
- constructor(key, value) {
4207
+ constructor(...args) {
4221
4208
  this.items = new Map();
4222
- if (key != null) {
4209
+ if (args.length === 1) {
4210
+ // 数组|对象
4211
+ const data = args[0];
4212
+ if (Array.isArray(data)) {
4213
+ // 数组
4214
+ // [[1,2], [3,4], ...]
4215
+ for (let index = 0; index < data.length; index++) {
4216
+ const item = data[index];
4217
+ if (Array.isArray(item)) {
4218
+ const [key, value] = item;
4219
+ this.set(key, value);
4220
+ }
4221
+ }
4222
+ }
4223
+ else if (typeof data === "object" && data != null) {
4224
+ // 对象
4225
+ // {1:2, 3:4}
4226
+ for (const key in data) {
4227
+ if (Reflect.has(data, key)) {
4228
+ this.set(key, data[key]);
4229
+ }
4230
+ }
4231
+ }
4232
+ }
4233
+ else if (args.length === 2) {
4234
+ // 键、值
4235
+ const [key, value] = args;
4223
4236
  this.set(key, value);
4224
4237
  }
4225
4238
  }
@@ -4235,7 +4248,7 @@
4235
4248
  get entries() {
4236
4249
  const that = this;
4237
4250
  return function* () {
4238
- const itemKeys = Object.keys(that.getItems());
4251
+ const itemKeys = that.keys();
4239
4252
  for (const keyName of itemKeys) {
4240
4253
  yield [keyName, that.get(keyName)];
4241
4254
  }
@@ -4272,7 +4285,7 @@
4272
4285
  */
4273
4286
  set(key, val) {
4274
4287
  if (key === void 0) {
4275
- throw new Error("Utils.Dictionary().set 参数 key 不能为空");
4288
+ throw new Error("Utils.Dictionary().set 参数 key 不能为undefined");
4276
4289
  }
4277
4290
  this.items.set(key, val);
4278
4291
  }
@@ -4910,403 +4923,401 @@
4910
4923
  const setInterval = (...args) => loadOrReturnBroker().setInterval(...args);
4911
4924
  const setTimeout$1 = (...args) => loadOrReturnBroker().setTimeout(...args);
4912
4925
 
4913
- /* eslint-disable */
4914
- // ==UserScript==
4915
- // @name ModuleRaid.js
4916
- // @namespace http://tampermonkey.net/
4917
- // @version 6.2.0
4918
- // @description 检索调用webpackJsonp模块,可指定检索的window
4919
- // @author empyrealtear
4920
- // @license MIT
4921
- // @original-script https://github.com/pixeldesu/moduleRaid
4922
- // ==/UserScript==
4923
-
4924
-
4925
- /**
4926
- * Main moduleRaid class
4927
- * @link https://scriptcat.org/zh-CN/script-show-page/2628
4928
- */
4929
- class ModuleRaid {
4930
- /**
4931
- * moduleRaid constructor
4932
- *
4933
- * @example
4934
- * Constructing an instance without any arguments:
4935
- * ```ts
4936
- * const mR = new ModuleRaid()
4937
- * ```
4938
- *
4939
- * Constructing an instance with the optional `opts` object:
4940
- * ```ts
4941
- * const mR = new ModuleRaid({ entrypoint: 'webpackChunk_custom_name' })
4942
- * ```
4943
- *
4944
- * @param opts a object containing options to initialize moduleRaid with
4945
- * - **opts:**
4946
- * - _target_: the window object being searched for
4947
- * - _entrypoint_: the Webpack entrypoint present on the global window object
4948
- * - _debug_: whether debug mode is enabled or not
4949
- * - _strict_: whether strict mode is enabled or not
4950
- */
4951
- constructor(opts) {
4952
- /**
4953
- * A random generated module ID we use for injecting into Webpack
4954
- */
4955
- this.moduleID = Math.random().toString(36).substring(7);
4956
- /**
4957
- * An array containing different argument injection methods for
4958
- * Webpack (before version 4), and subsequently pulling out methods and modules
4959
- * @internal
4960
- */
4961
- this.functionArguments = [
4962
- [
4963
- [0],
4964
- [
4965
- (_e, _t, i) => {
4966
- this.modules = i.c;
4967
- this.constructors = i.m;
4968
- this.get = i;
4969
- },
4970
- ],
4971
- ],
4972
- [
4973
- [1e3],
4974
- {
4975
- [this.moduleID]: (_e, _t, i) => {
4976
- this.modules = i.c;
4977
- this.constructors = i.m;
4978
- this.get = i;
4979
- },
4980
- },
4981
- [[this.moduleID]],
4982
- ],
4983
- ];
4984
- /**
4985
- * An array containing different argument injection methods for
4986
- * Webpack (after version 4), and subsequently pulling out methods and modules
4987
- * @internal
4988
- */
4989
- this.arrayArguments = [
4990
- [
4991
- [this.moduleID],
4992
- {},
4993
- (e) => {
4994
- const mCac = e.m;
4995
- Object.keys(mCac).forEach((mod) => {
4996
- try {
4997
- this.modules[mod] = e(mod);
4998
- }
4999
- catch (err) {
5000
- this.log(`[arrayArguments/1] Failed to require(${mod}) with error:\n${err}\n${err.stack}`);
5001
- }
5002
- });
5003
- this.get = e;
5004
- },
5005
- ],
5006
- this.functionArguments[1],
5007
- ];
5008
- /**
5009
- * Storage for the modules we extracted from Webpack
5010
- */
5011
- this.modules = {};
5012
- /**
5013
- * Storage for the constructors we extracted from Webpack
5014
- */
5015
- this.constructors = [];
5016
- let options = {
5017
- target: window,
5018
- entrypoint: 'webpackJsonp',
5019
- debug: false,
5020
- strict: false,
5021
- };
5022
- if (typeof opts === 'object') {
5023
- options = Object.assign(Object.assign({}, options), opts);
5024
- }
5025
- this.target = options.target;
5026
- this.entrypoint = options.entrypoint;
5027
- this.debug = options.debug;
5028
- this.strict = options.strict;
5029
- this.detectEntrypoint();
5030
- this.fillModules();
5031
- this.replaceGet();
5032
- this.setupPushEvent();
5033
- }
5034
- /**
5035
- * Debug logging method, outputs to the console when {@link ModuleRaid.debug} is true
5036
- *
5037
- * @param {*} message The message to be logged
5038
- * @internal
5039
- */
5040
- log(message) {
5041
- if (this.debug) {
5042
- console.warn(`[moduleRaid] ${message}`);
5043
- }
5044
- }
5045
- /**
5046
- * Method to set an alternative getter if we weren't able to extract __webpack_require__
5047
- * from Webpack
5048
- * @internal
5049
- */
5050
- replaceGet() {
5051
- if (this.get === null) {
5052
- this.get = (key) => this.modules[key];
5053
- }
5054
- }
5055
- /**
5056
- * Method that will try to inject a module into Webpack or get modules
5057
- * depending on it's success it might be more or less brute about it
5058
- * @internal
5059
- */
5060
- fillModules() {
5061
- if (typeof this.target[this.entrypoint] === 'function') {
5062
- this.functionArguments.forEach((argument, index) => {
5063
- try {
5064
- if (this.modules && Object.keys(this.modules).length > 0)
5065
- return;
5066
- this.target[this.entrypoint](...argument);
5067
- }
5068
- catch (err) {
5069
- this.log(`moduleRaid.functionArguments[${index}] failed:\n${err}\n${err.stack}`);
5070
- }
5071
- });
5072
- }
5073
- else {
5074
- this.arrayArguments.forEach((argument, index) => {
5075
- try {
5076
- if (this.modules && Object.keys(this.modules).length > 0)
5077
- return;
5078
- this.target[this.entrypoint].push(argument);
5079
- }
5080
- catch (err) {
5081
- this.log(`Pushing moduleRaid.arrayArguments[${index}] into ${this.entrypoint} failed:\n${err}\n${err.stack}`);
5082
- }
5083
- });
5084
- }
5085
- if (this.modules && Object.keys(this.modules).length == 0) {
5086
- let moduleEnd = false;
5087
- let moduleIterator = 0;
5088
- if (typeof this.target[this.entrypoint] != 'function' || !this.target[this.entrypoint]([], [], [moduleIterator])) {
5089
- throw Error('Unknown Webpack structure');
5090
- }
5091
- while (!moduleEnd) {
5092
- try {
5093
- this.modules[moduleIterator] = this.target[this.entrypoint]([], [], [moduleIterator]);
5094
- moduleIterator++;
5095
- }
5096
- catch (err) {
5097
- moduleEnd = true;
5098
- }
5099
- }
5100
- }
5101
- }
5102
- /**
5103
- * Method to hook into `window[this.entrypoint].push` adding a listener for new
5104
- * chunks being pushed into Webpack
5105
- *
5106
- * @example
5107
- * You can listen for newly pushed packages using the `moduleraid:webpack-push` event
5108
- * on `document`
5109
- *
5110
- * ```ts
5111
- * document.addEventListener('moduleraid:webpack-push', (e) => {
5112
- * // e.detail contains the arguments push() was called with
5113
- * console.log(e.detail)
5114
- * })
5115
- * ```
5116
- * @internal
5117
- */
5118
- setupPushEvent() {
5119
- const originalPush = this.target[this.entrypoint].push;
5120
- this.target[this.entrypoint].push = (...args) => {
5121
- const result = Reflect.apply(originalPush, this.target[this.entrypoint], args);
5122
- document.dispatchEvent(new CustomEvent('moduleraid:webpack-push', { detail: args }));
5123
- return result;
5124
- };
5125
- }
5126
- /**
5127
- * Method to try autodetecting a Webpack JSONP entrypoint based on common naming
5128
- *
5129
- * If the default entrypoint, or the entrypoint that's passed to the moduleRaid constructor
5130
- * already matches, the method exits early
5131
- *
5132
- * If `options.strict` has been set in the constructor and the initial entrypoint cannot
5133
- * be found, this method will error, demanding a strictly set entrypoint
5134
- * @internal
5135
- */
5136
- detectEntrypoint() {
5137
- if (this.target[this.entrypoint] != undefined) {
5138
- return;
5139
- }
5140
- if (this.strict) {
5141
- throw Error(`Strict mode is enabled and entrypoint at window.${this.entrypoint} couldn't be found. Please specify the correct one!`);
5142
- }
5143
- let windowObjects = Object.keys(this.target);
5144
- windowObjects = windowObjects
5145
- .filter((object) => object.toLowerCase().includes('chunk') || object.toLowerCase().includes('webpack'))
5146
- .filter((object) => typeof this.target[object] === 'function' || Array.isArray(this.target[object]));
5147
- if (windowObjects.length > 1) {
5148
- throw Error(`Multiple possible endpoints have been detected, please create a new moduleRaid instance with a specific one:\n${windowObjects.join(', ')}`);
5149
- }
5150
- if (windowObjects.length === 0) {
5151
- throw Error('No Webpack JSONP entrypoints could be detected');
5152
- }
5153
- this.log(`Entrypoint has been detected at window.${windowObjects[0]} and set for injection`);
5154
- this.entrypoint = windowObjects[0];
5155
- }
5156
- /**
5157
- * Recursive object-search function for modules
5158
- *
5159
- * @param object the object to search through
5160
- * @param query the query the object keys/values are searched for
5161
- * @returns boolean state of `object` containing `query` somewhere in it
5162
- * @internal
5163
- */
5164
- searchObject(object, query) {
5165
- for (const key in object) {
5166
- const value = object[key];
5167
- const lowerCaseQuery = query.toLowerCase();
5168
- if (typeof value != 'object') {
5169
- const lowerCaseKey = key.toString().toLowerCase();
5170
- if (lowerCaseKey.includes(lowerCaseQuery))
5171
- return true;
5172
- if (typeof value != 'object') {
5173
- const lowerCaseValue = value.toString().toLowerCase();
5174
- if (lowerCaseValue.includes(lowerCaseQuery))
5175
- return true;
5176
- }
5177
- else {
5178
- if (this.searchObject(value, query))
5179
- return true;
5180
- }
5181
- }
5182
- }
5183
- return false;
5184
- }
5185
- /**
5186
- * Method to search through the module object, searching for the fitting content
5187
- * if a string is supplied
5188
- *
5189
- * If query is supplied as a function, everything that returns true when passed
5190
- * to the query function will be returned
5191
- *
5192
- * @example
5193
- * With a string as query argument:
5194
- * ```ts
5195
- * const results = mR.findModule('feature')
5196
- * // => Array of module results
5197
- * ```
5198
- *
5199
- * With a function as query argument:
5200
- * ```ts
5201
- * const results = mR.findModule((module) => { typeof module === 'function' })
5202
- * // => Array of module results
5203
- * ```
5204
- *
5205
- * @param query query to search the module list for
5206
- * @return a list of modules fitting the query
5207
- */
5208
- findModule(query) {
5209
- const results = [];
5210
- const modules = Object.keys(this.modules);
5211
- if (modules.length === 0) {
5212
- throw new Error('There are no modules to search through!');
5213
- }
5214
- modules.forEach((key) => {
5215
- const module = this.modules[key.toString()];
5216
- if (module === undefined)
5217
- return;
5218
- try {
5219
- if (typeof query === 'string') {
5220
- query = query.toLowerCase();
5221
- switch (typeof module) {
5222
- case 'string':
5223
- if (module.toLowerCase().includes(query))
5224
- results.push(module);
5225
- break;
5226
- case 'function':
5227
- if (module.toString().toLowerCase().includes(query))
5228
- results.push(module);
5229
- break;
5230
- case 'object':
5231
- if (this.searchObject(module, query))
5232
- results.push(module);
5233
- break;
5234
- }
5235
- }
5236
- else if (typeof query === 'function') {
5237
- if (query(module))
5238
- results.push(module);
5239
- }
5240
- else {
5241
- throw new TypeError(`findModule can only find via string and function, ${typeof query} was passed`);
5242
- }
5243
- }
5244
- catch (err) {
5245
- this.log(`There was an error while searching through module '${key}':\n${err}\n${err.stack}`);
5246
- }
5247
- });
5248
- return results;
5249
- }
5250
- /**
5251
- * Method to search through the constructor array, searching for the fitting content
5252
- * if a string is supplied
5253
- *
5254
- * If query is supplied as a function, everything that returns true when passed
5255
- * to the query function will be returned
5256
- *
5257
- * @example
5258
- * With a string as query argument:
5259
- * ```ts
5260
- * const results = mR.findConstructor('feature')
5261
- * // => Array of constructor/module tuples
5262
- * ```
5263
- *
5264
- * With a function as query argument:
5265
- * ```ts
5266
- * const results = mR.findConstructor((constructor) => { constructor.prototype.value !== undefined })
5267
- * // => Array of constructor/module tuples
5268
- * ```
5269
- *
5270
- * Accessing the resulting data:
5271
- * ```ts
5272
- * // With array destructuring (ES6)
5273
- * const [constructor, module] = results[0]
5274
- *
5275
- * // ...or...
5276
- *
5277
- * // regular access
5278
- * const constructor = results[0][0]
5279
- * const module = results[0][1]
5280
- * ```
5281
- *
5282
- * @param query query to search the constructor list for
5283
- * @returns a list of constructor/module tuples fitting the query
5284
- */
5285
- findConstructor(query) {
5286
- const results = [];
5287
- const constructors = Object.keys(this.constructors);
5288
- if (constructors.length === 0) {
5289
- throw new Error('There are no constructors to search through!');
5290
- }
5291
- constructors.forEach((key) => {
5292
- const constructor = this.constructors[key];
5293
- try {
5294
- if (typeof query === 'string') {
5295
- query = query.toLowerCase();
5296
- if (constructor.toString().toLowerCase().includes(query))
5297
- results.push([this.constructors[key], this.modules[key]]);
5298
- }
5299
- else if (typeof query === 'function') {
5300
- if (query(constructor))
5301
- results.push([this.constructors[key], this.modules[key]]);
5302
- }
5303
- }
5304
- catch (err) {
5305
- this.log(`There was an error while searching through constructor '${key}':\n${err}\n${err.stack}`);
5306
- }
5307
- });
5308
- return results;
5309
- }
4926
+ /* eslint-disable */
4927
+ // ==UserScript==
4928
+ // @name ModuleRaid.js
4929
+ // @namespace http://tampermonkey.net/
4930
+ // @version 6.2.0
4931
+ // @description 检索调用webpackJsonp模块,可指定检索的window
4932
+ // @author empyrealtear
4933
+ // @license MIT
4934
+ // @original-script https://github.com/pixeldesu/moduleRaid
4935
+ // ==/UserScript==
4936
+ /**
4937
+ * Main moduleRaid class
4938
+ * @link https://scriptcat.org/zh-CN/script-show-page/2628
4939
+ */
4940
+ class ModuleRaid {
4941
+ /**
4942
+ * moduleRaid constructor
4943
+ *
4944
+ * @example
4945
+ * Constructing an instance without any arguments:
4946
+ * ```ts
4947
+ * const mR = new ModuleRaid()
4948
+ * ```
4949
+ *
4950
+ * Constructing an instance with the optional `opts` object:
4951
+ * ```ts
4952
+ * const mR = new ModuleRaid({ entrypoint: 'webpackChunk_custom_name' })
4953
+ * ```
4954
+ *
4955
+ * @param opts a object containing options to initialize moduleRaid with
4956
+ * - **opts:**
4957
+ * - _target_: the window object being searched for
4958
+ * - _entrypoint_: the Webpack entrypoint present on the global window object
4959
+ * - _debug_: whether debug mode is enabled or not
4960
+ * - _strict_: whether strict mode is enabled or not
4961
+ */
4962
+ constructor(opts) {
4963
+ /**
4964
+ * A random generated module ID we use for injecting into Webpack
4965
+ */
4966
+ this.moduleID = Math.random().toString(36).substring(7);
4967
+ /**
4968
+ * An array containing different argument injection methods for
4969
+ * Webpack (before version 4), and subsequently pulling out methods and modules
4970
+ * @internal
4971
+ */
4972
+ this.functionArguments = [
4973
+ [
4974
+ [0],
4975
+ [
4976
+ (_e, _t, i) => {
4977
+ this.modules = i.c;
4978
+ this.constructors = i.m;
4979
+ this.get = i;
4980
+ },
4981
+ ],
4982
+ ],
4983
+ [
4984
+ [1e3],
4985
+ {
4986
+ [this.moduleID]: (_e, _t, i) => {
4987
+ this.modules = i.c;
4988
+ this.constructors = i.m;
4989
+ this.get = i;
4990
+ },
4991
+ },
4992
+ [[this.moduleID]],
4993
+ ],
4994
+ ];
4995
+ /**
4996
+ * An array containing different argument injection methods for
4997
+ * Webpack (after version 4), and subsequently pulling out methods and modules
4998
+ * @internal
4999
+ */
5000
+ this.arrayArguments = [
5001
+ [
5002
+ [this.moduleID],
5003
+ {},
5004
+ (e) => {
5005
+ const mCac = e.m;
5006
+ Object.keys(mCac).forEach((mod) => {
5007
+ try {
5008
+ this.modules[mod] = e(mod);
5009
+ }
5010
+ catch (err) {
5011
+ this.log(`[arrayArguments/1] Failed to require(${mod}) with error:\n${err}\n${err.stack}`);
5012
+ }
5013
+ });
5014
+ this.get = e;
5015
+ },
5016
+ ],
5017
+ this.functionArguments[1],
5018
+ ];
5019
+ /**
5020
+ * Storage for the modules we extracted from Webpack
5021
+ */
5022
+ this.modules = {};
5023
+ /**
5024
+ * Storage for the constructors we extracted from Webpack
5025
+ */
5026
+ this.constructors = [];
5027
+ let options = {
5028
+ target: window,
5029
+ entrypoint: 'webpackJsonp',
5030
+ debug: false,
5031
+ strict: false,
5032
+ };
5033
+ if (typeof opts === 'object') {
5034
+ options = Object.assign(Object.assign({}, options), opts);
5035
+ }
5036
+ this.target = options.target;
5037
+ this.entrypoint = options.entrypoint;
5038
+ this.debug = options.debug;
5039
+ this.strict = options.strict;
5040
+ this.detectEntrypoint();
5041
+ this.fillModules();
5042
+ this.replaceGet();
5043
+ this.setupPushEvent();
5044
+ }
5045
+ /**
5046
+ * Debug logging method, outputs to the console when {@link ModuleRaid.debug} is true
5047
+ *
5048
+ * @param {*} message The message to be logged
5049
+ * @internal
5050
+ */
5051
+ log(message) {
5052
+ if (this.debug) {
5053
+ console.warn(`[moduleRaid] ${message}`);
5054
+ }
5055
+ }
5056
+ /**
5057
+ * Method to set an alternative getter if we weren't able to extract __webpack_require__
5058
+ * from Webpack
5059
+ * @internal
5060
+ */
5061
+ replaceGet() {
5062
+ if (this.get === null) {
5063
+ this.get = (key) => this.modules[key];
5064
+ }
5065
+ }
5066
+ /**
5067
+ * Method that will try to inject a module into Webpack or get modules
5068
+ * depending on it's success it might be more or less brute about it
5069
+ * @internal
5070
+ */
5071
+ fillModules() {
5072
+ if (typeof this.target[this.entrypoint] === 'function') {
5073
+ this.functionArguments.forEach((argument, index) => {
5074
+ try {
5075
+ if (this.modules && Object.keys(this.modules).length > 0)
5076
+ return;
5077
+ this.target[this.entrypoint](...argument);
5078
+ }
5079
+ catch (err) {
5080
+ this.log(`moduleRaid.functionArguments[${index}] failed:\n${err}\n${err.stack}`);
5081
+ }
5082
+ });
5083
+ }
5084
+ else {
5085
+ this.arrayArguments.forEach((argument, index) => {
5086
+ try {
5087
+ if (this.modules && Object.keys(this.modules).length > 0)
5088
+ return;
5089
+ this.target[this.entrypoint].push(argument);
5090
+ }
5091
+ catch (err) {
5092
+ this.log(`Pushing moduleRaid.arrayArguments[${index}] into ${this.entrypoint} failed:\n${err}\n${err.stack}`);
5093
+ }
5094
+ });
5095
+ }
5096
+ if (this.modules && Object.keys(this.modules).length == 0) {
5097
+ let moduleEnd = false;
5098
+ let moduleIterator = 0;
5099
+ if (typeof this.target[this.entrypoint] != 'function' || !this.target[this.entrypoint]([], [], [moduleIterator])) {
5100
+ throw Error('Unknown Webpack structure');
5101
+ }
5102
+ while (!moduleEnd) {
5103
+ try {
5104
+ this.modules[moduleIterator] = this.target[this.entrypoint]([], [], [moduleIterator]);
5105
+ moduleIterator++;
5106
+ }
5107
+ catch (err) {
5108
+ moduleEnd = true;
5109
+ }
5110
+ }
5111
+ }
5112
+ }
5113
+ /**
5114
+ * Method to hook into `window[this.entrypoint].push` adding a listener for new
5115
+ * chunks being pushed into Webpack
5116
+ *
5117
+ * @example
5118
+ * You can listen for newly pushed packages using the `moduleraid:webpack-push` event
5119
+ * on `document`
5120
+ *
5121
+ * ```ts
5122
+ * document.addEventListener('moduleraid:webpack-push', (e) => {
5123
+ * // e.detail contains the arguments push() was called with
5124
+ * console.log(e.detail)
5125
+ * })
5126
+ * ```
5127
+ * @internal
5128
+ */
5129
+ setupPushEvent() {
5130
+ const originalPush = this.target[this.entrypoint].push;
5131
+ this.target[this.entrypoint].push = (...args) => {
5132
+ const result = Reflect.apply(originalPush, this.target[this.entrypoint], args);
5133
+ document.dispatchEvent(new CustomEvent('moduleraid:webpack-push', { detail: args }));
5134
+ return result;
5135
+ };
5136
+ }
5137
+ /**
5138
+ * Method to try autodetecting a Webpack JSONP entrypoint based on common naming
5139
+ *
5140
+ * If the default entrypoint, or the entrypoint that's passed to the moduleRaid constructor
5141
+ * already matches, the method exits early
5142
+ *
5143
+ * If `options.strict` has been set in the constructor and the initial entrypoint cannot
5144
+ * be found, this method will error, demanding a strictly set entrypoint
5145
+ * @internal
5146
+ */
5147
+ detectEntrypoint() {
5148
+ if (this.target[this.entrypoint] != undefined) {
5149
+ return;
5150
+ }
5151
+ if (this.strict) {
5152
+ throw Error(`Strict mode is enabled and entrypoint at window.${this.entrypoint} couldn't be found. Please specify the correct one!`);
5153
+ }
5154
+ let windowObjects = Object.keys(this.target);
5155
+ windowObjects = windowObjects
5156
+ .filter((object) => object.toLowerCase().includes('chunk') || object.toLowerCase().includes('webpack'))
5157
+ .filter((object) => typeof this.target[object] === 'function' || Array.isArray(this.target[object]));
5158
+ if (windowObjects.length > 1) {
5159
+ throw Error(`Multiple possible endpoints have been detected, please create a new moduleRaid instance with a specific one:\n${windowObjects.join(', ')}`);
5160
+ }
5161
+ if (windowObjects.length === 0) {
5162
+ throw Error('No Webpack JSONP entrypoints could be detected');
5163
+ }
5164
+ this.log(`Entrypoint has been detected at window.${windowObjects[0]} and set for injection`);
5165
+ this.entrypoint = windowObjects[0];
5166
+ }
5167
+ /**
5168
+ * Recursive object-search function for modules
5169
+ *
5170
+ * @param object the object to search through
5171
+ * @param query the query the object keys/values are searched for
5172
+ * @returns boolean state of `object` containing `query` somewhere in it
5173
+ * @internal
5174
+ */
5175
+ searchObject(object, query) {
5176
+ for (const key in object) {
5177
+ const value = object[key];
5178
+ const lowerCaseQuery = query.toLowerCase();
5179
+ if (typeof value != 'object') {
5180
+ const lowerCaseKey = key.toString().toLowerCase();
5181
+ if (lowerCaseKey.includes(lowerCaseQuery))
5182
+ return true;
5183
+ if (typeof value != 'object') {
5184
+ const lowerCaseValue = value.toString().toLowerCase();
5185
+ if (lowerCaseValue.includes(lowerCaseQuery))
5186
+ return true;
5187
+ }
5188
+ else {
5189
+ if (this.searchObject(value, query))
5190
+ return true;
5191
+ }
5192
+ }
5193
+ }
5194
+ return false;
5195
+ }
5196
+ /**
5197
+ * Method to search through the module object, searching for the fitting content
5198
+ * if a string is supplied
5199
+ *
5200
+ * If query is supplied as a function, everything that returns true when passed
5201
+ * to the query function will be returned
5202
+ *
5203
+ * @example
5204
+ * With a string as query argument:
5205
+ * ```ts
5206
+ * const results = mR.findModule('feature')
5207
+ * // => Array of module results
5208
+ * ```
5209
+ *
5210
+ * With a function as query argument:
5211
+ * ```ts
5212
+ * const results = mR.findModule((module) => { typeof module === 'function' })
5213
+ * // => Array of module results
5214
+ * ```
5215
+ *
5216
+ * @param query query to search the module list for
5217
+ * @return a list of modules fitting the query
5218
+ */
5219
+ findModule(query) {
5220
+ const results = [];
5221
+ const modules = Object.keys(this.modules);
5222
+ if (modules.length === 0) {
5223
+ throw new Error('There are no modules to search through!');
5224
+ }
5225
+ modules.forEach((key) => {
5226
+ const module = this.modules[key.toString()];
5227
+ if (module === undefined)
5228
+ return;
5229
+ try {
5230
+ if (typeof query === 'string') {
5231
+ query = query.toLowerCase();
5232
+ switch (typeof module) {
5233
+ case 'string':
5234
+ if (module.toLowerCase().includes(query))
5235
+ results.push(module);
5236
+ break;
5237
+ case 'function':
5238
+ if (module.toString().toLowerCase().includes(query))
5239
+ results.push(module);
5240
+ break;
5241
+ case 'object':
5242
+ if (this.searchObject(module, query))
5243
+ results.push(module);
5244
+ break;
5245
+ }
5246
+ }
5247
+ else if (typeof query === 'function') {
5248
+ if (query(module))
5249
+ results.push(module);
5250
+ }
5251
+ else {
5252
+ throw new TypeError(`findModule can only find via string and function, ${typeof query} was passed`);
5253
+ }
5254
+ }
5255
+ catch (err) {
5256
+ this.log(`There was an error while searching through module '${key}':\n${err}\n${err.stack}`);
5257
+ }
5258
+ });
5259
+ return results;
5260
+ }
5261
+ /**
5262
+ * Method to search through the constructor array, searching for the fitting content
5263
+ * if a string is supplied
5264
+ *
5265
+ * If query is supplied as a function, everything that returns true when passed
5266
+ * to the query function will be returned
5267
+ *
5268
+ * @example
5269
+ * With a string as query argument:
5270
+ * ```ts
5271
+ * const results = mR.findConstructor('feature')
5272
+ * // => Array of constructor/module tuples
5273
+ * ```
5274
+ *
5275
+ * With a function as query argument:
5276
+ * ```ts
5277
+ * const results = mR.findConstructor((constructor) => { constructor.prototype.value !== undefined })
5278
+ * // => Array of constructor/module tuples
5279
+ * ```
5280
+ *
5281
+ * Accessing the resulting data:
5282
+ * ```ts
5283
+ * // With array destructuring (ES6)
5284
+ * const [constructor, module] = results[0]
5285
+ *
5286
+ * // ...or...
5287
+ *
5288
+ * // regular access
5289
+ * const constructor = results[0][0]
5290
+ * const module = results[0][1]
5291
+ * ```
5292
+ *
5293
+ * @param query query to search the constructor list for
5294
+ * @returns a list of constructor/module tuples fitting the query
5295
+ */
5296
+ findConstructor(query) {
5297
+ const results = [];
5298
+ const constructors = Object.keys(this.constructors);
5299
+ if (constructors.length === 0) {
5300
+ throw new Error('There are no constructors to search through!');
5301
+ }
5302
+ constructors.forEach((key) => {
5303
+ const constructor = this.constructors[key];
5304
+ try {
5305
+ if (typeof query === 'string') {
5306
+ query = query.toLowerCase();
5307
+ if (constructor.toString().toLowerCase().includes(query))
5308
+ results.push([this.constructors[key], this.modules[key]]);
5309
+ }
5310
+ else if (typeof query === 'function') {
5311
+ if (query(constructor))
5312
+ results.push([this.constructors[key], this.modules[key]]);
5313
+ }
5314
+ }
5315
+ catch (err) {
5316
+ this.log(`There was an error while searching through constructor '${key}':\n${err}\n${err.stack}`);
5317
+ }
5318
+ });
5319
+ return results;
5320
+ }
5310
5321
  }
5311
5322
 
5312
5323
  class DOMUtils {
@@ -5478,7 +5489,7 @@
5478
5489
  }
5479
5490
  const domUtils = new DOMUtils();
5480
5491
 
5481
- const version = "2.9.3";
5492
+ const version = "2.9.5";
5482
5493
 
5483
5494
  class Utils {
5484
5495
  windowApi;