@whitesev/utils 2.9.4 → 2.9.5

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