@whitesev/utils 2.9.4 → 2.9.6

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