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