@whitesev/utils 2.7.3 → 2.7.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.
@@ -10,4 +10,8 @@ export declare class WindowApi {
10
10
  get globalThis(): typeof globalThis | Window;
11
11
  get self(): Window & typeof globalThis;
12
12
  get top(): Window;
13
+ get setTimeout(): (handler: TimerHandler, timeout?: number, ...arguments: any[]) => number;
14
+ get setInterval(): (handler: TimerHandler, timeout?: number, ...arguments: any[]) => number;
15
+ get clearTimeout(): (id: number | undefined) => void;
16
+ get clearInterval(): (id: number | undefined) => void;
13
17
  }
@@ -7,4 +7,8 @@ export type WindowApiOption = {
7
7
  globalThis?: typeof globalThis | Window;
8
8
  self?: Window & typeof globalThis;
9
9
  top: Window;
10
+ setTimeout: Window["setTimeout"];
11
+ setInterval: Window["setInterval"];
12
+ clearTimeout: Window["clearTimeout"];
13
+ clearInterval: Window["clearInterval"];
10
14
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@whitesev/utils",
4
- "version": "2.7.3",
4
+ "version": "2.7.5",
5
5
  "type": "module",
6
6
  "description": "一个常用的工具库",
7
7
  "main": "dist/index.cjs.js",
package/src/Utils.ts CHANGED
@@ -35,7 +35,7 @@ class Utils {
35
35
  this.windowApi = new WindowApi(option);
36
36
  }
37
37
  /** 版本号 */
38
- version = "2025.8.11";
38
+ version = "2025.8.21";
39
39
  /**
40
40
  * 在页面中增加style元素,如果html节点存在子节点,添加子节点第一个,反之,添加到html节点的子节点最后一个
41
41
  * @param cssText css字符串
@@ -4698,7 +4698,7 @@ class Utils {
4698
4698
  try {
4699
4699
  return WorkerSetTimeout(callback, timeout);
4700
4700
  } catch (error) {
4701
- return globalThis.setTimeout(callback, timeout);
4701
+ return this.windowApi.setTimeout(callback, timeout);
4702
4702
  }
4703
4703
  }
4704
4704
  /**
@@ -4712,7 +4712,7 @@ class Utils {
4712
4712
  }
4713
4713
  } catch (error) {
4714
4714
  } finally {
4715
- globalThis.clearTimeout(timeId);
4715
+ this.windowApi.clearTimeout(timeId);
4716
4716
  }
4717
4717
  }
4718
4718
  /**
@@ -4724,7 +4724,7 @@ class Utils {
4724
4724
  try {
4725
4725
  return WorkerSetInterval(callback, timeout);
4726
4726
  } catch (error) {
4727
- return globalThis.setInterval(callback, timeout);
4727
+ return this.windowApi.setInterval(callback, timeout);
4728
4728
  }
4729
4729
  }
4730
4730
  /**
@@ -4738,7 +4738,7 @@ class Utils {
4738
4738
  }
4739
4739
  } catch (error) {
4740
4740
  } finally {
4741
- globalThis.clearInterval(timeId);
4741
+ this.windowApi.clearInterval(timeId);
4742
4742
  }
4743
4743
  }
4744
4744
  /**
package/src/WindowApi.ts CHANGED
@@ -8,6 +8,10 @@ export class WindowApi {
8
8
  globalThis: globalThis,
9
9
  self: self,
10
10
  top: top!,
11
+ setTimeout: globalThis.setTimeout.bind(globalThis),
12
+ setInterval: globalThis.setInterval.bind(globalThis),
13
+ clearTimeout: globalThis.clearTimeout.bind(globalThis),
14
+ clearInterval: globalThis.clearInterval.bind(globalThis),
11
15
  };
12
16
  /** 使用的配置 */
13
17
  private api: Required<WindowApiOption>;
@@ -40,4 +44,16 @@ export class WindowApi {
40
44
  get top() {
41
45
  return this.api.top;
42
46
  }
47
+ get setTimeout() {
48
+ return this.api.setTimeout;
49
+ }
50
+ get setInterval() {
51
+ return this.api.setInterval;
52
+ }
53
+ get clearTimeout() {
54
+ return this.api.clearTimeout;
55
+ }
56
+ get clearInterval() {
57
+ return this.api.clearInterval;
58
+ }
43
59
  }
@@ -1,14 +1,14 @@
1
1
  // ==UserScript==
2
2
  // @name ajaxHooker
3
3
  // @author cxxjackie
4
- // @version 1.4.7
4
+ // @version 1.4.8
5
5
  // @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
6
6
  // @license GNU LGPL-3.0
7
7
  // ==/UserScript==
8
8
 
9
9
  export const ajaxHooker = function () {
10
10
  "use strict";
11
- const version = "1.4.7";
11
+ const version = "1.4.8";
12
12
  const hookInst = {
13
13
  hookFns: [],
14
14
  filters: [],
@@ -37,11 +37,7 @@ export const ajaxHooker = function () {
37
37
  const emptyFn = () => {};
38
38
  const errorFn = (e) => console.error(e);
39
39
  function isThenable(obj) {
40
- return (
41
- obj &&
42
- ["object", "function"].includes(typeof obj) &&
43
- typeof obj.then === "function"
44
- );
40
+ return obj && ["object", "function"].includes(typeof obj) && typeof obj.then === "function";
45
41
  }
46
42
  function catchError(fn, ...args) {
47
43
  try {
@@ -79,8 +75,7 @@ export const ajaxHooker = function () {
79
75
  const [header, value] = line.split(/(?<=^[^:]+)\s*:\s*/);
80
76
  if (!value) continue;
81
77
  const lheader = header.toLowerCase();
82
- headers[lheader] =
83
- lheader in headers ? `${headers[lheader]}, ${value}` : value;
78
+ headers[lheader] = lheader in headers ? `${headers[lheader]}, ${value}` : value;
84
79
  }
85
80
  break;
86
81
  case "[object Headers]":
@@ -118,11 +113,9 @@ export const ajaxHooker = function () {
118
113
  !filters.find((obj) => {
119
114
  switch (true) {
120
115
  case obj.type && obj.type !== type:
121
- case getType(obj.url) === "[object String]" &&
122
- !url.includes(obj.url):
116
+ case getType(obj.url) === "[object String]" && !url.includes(obj.url):
123
117
  case getType(obj.url) === "[object RegExp]" && !obj.url.test(url):
124
- case obj.method &&
125
- obj.method.toUpperCase() !== method.toUpperCase():
118
+ case obj.method && obj.method.toUpperCase() !== method.toUpperCase():
126
119
  case "async" in obj && obj.async !== async:
127
120
  return false;
128
121
  }
@@ -135,8 +128,7 @@ export const ajaxHooker = function () {
135
128
  win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
136
129
  if (this.shouldFilter(filters)) return;
137
130
  hookFns.forEach((fn) => {
138
- if (getType(fn) === "[object Function]")
139
- catchError(fn, this.request);
131
+ if (getType(fn) === "[object Function]") catchError(fn, this.request);
140
132
  });
141
133
  for (const key in this.request) {
142
134
  if (isThenable(this.request[key])) this._recoverRequestKey(key);
@@ -149,93 +141,72 @@ export const ajaxHooker = function () {
149
141
  win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
150
142
  if (this.shouldFilter(filters)) return;
151
143
  promises.push(
152
- Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
153
- () => {
154
- const requestKeys = [];
155
- for (const key in this.request)
156
- !ignoreKeys.has(key) && requestKeys.push(key);
157
- return Promise.all(
158
- requestKeys.map((key) =>
159
- Promise.resolve(this.request[key]).then(
160
- (val) => (this.request[key] = val),
161
- () => this._recoverRequestKey(key)
162
- )
144
+ Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(() => {
145
+ const requestKeys = [];
146
+ for (const key in this.request) !ignoreKeys.has(key) && requestKeys.push(key);
147
+ return Promise.all(
148
+ requestKeys.map((key) =>
149
+ Promise.resolve(this.request[key]).then(
150
+ (val) => (this.request[key] = val),
151
+ () => this._recoverRequestKey(key)
163
152
  )
164
- );
165
- }
166
- )
153
+ )
154
+ );
155
+ })
167
156
  );
168
157
  });
169
158
  return Promise.all(promises);
170
159
  }
171
160
  waitForResponseKeys(response) {
172
- const responseKeys =
173
- this.request.type === "xhr" ? xhrResponses : fetchResponses;
161
+ const responseKeys = this.request.type === "xhr" ? xhrResponses : fetchResponses;
174
162
  if (!this.request.async) {
175
163
  if (getType(this.request.response) === "[object Function]") {
176
164
  catchError(this.request.response, response);
177
165
  responseKeys.forEach((key) => {
178
- if (
179
- "get" in getDescriptor(response, key) ||
180
- isThenable(response[key])
181
- ) {
166
+ if ("get" in getDescriptor(response, key) || isThenable(response[key])) {
182
167
  delete response[key];
183
168
  }
184
169
  });
185
170
  }
186
171
  return new SyncThenable();
187
172
  }
188
- return Promise.resolve(catchError(this.request.response, response)).then(
189
- () =>
190
- Promise.all(
191
- responseKeys.map((key) => {
192
- const descriptor = getDescriptor(response, key);
193
- if (descriptor && "value" in descriptor) {
194
- return Promise.resolve(descriptor.value).then(
195
- (val) => (response[key] = val),
196
- () => delete response[key]
197
- );
198
- } else {
199
- delete response[key];
200
- }
201
- })
202
- )
173
+ return Promise.resolve(catchError(this.request.response, response)).then(() =>
174
+ Promise.all(
175
+ responseKeys.map((key) => {
176
+ const descriptor = getDescriptor(response, key);
177
+ if (descriptor && "value" in descriptor) {
178
+ return Promise.resolve(descriptor.value).then(
179
+ (val) => (response[key] = val),
180
+ () => delete response[key]
181
+ );
182
+ } else {
183
+ delete response[key];
184
+ }
185
+ })
186
+ )
203
187
  );
204
188
  }
205
189
  }
206
190
  const proxyHandler = {
207
191
  get(target, prop) {
208
192
  const descriptor = getDescriptor(target, prop);
209
- if (
210
- descriptor &&
211
- !descriptor.configurable &&
212
- !descriptor.writable &&
213
- !descriptor.get
214
- )
193
+ if (descriptor && !descriptor.configurable && !descriptor.writable && !descriptor.get)
215
194
  return target[prop];
216
195
  const ah = target.__ajaxHooker;
217
196
  if (ah && ah.proxyProps) {
218
197
  if (prop in ah.proxyProps) {
219
198
  const pDescriptor = ah.proxyProps[prop];
220
199
  if ("get" in pDescriptor) return pDescriptor.get();
221
- if (typeof pDescriptor.value === "function")
222
- return pDescriptor.value.bind(ah);
200
+ if (typeof pDescriptor.value === "function") return pDescriptor.value.bind(ah);
223
201
  return pDescriptor.value;
224
202
  }
225
- if (typeof target[prop] === "function")
226
- return target[prop].bind(target);
203
+ if (typeof target[prop] === "function") return target[prop].bind(target);
227
204
  }
228
205
  return target[prop];
229
206
  },
230
207
  set(target, prop, value) {
231
208
  const descriptor = getDescriptor(target, prop);
232
- if (
233
- descriptor &&
234
- !descriptor.configurable &&
235
- !descriptor.writable &&
236
- !descriptor.set
237
- )
238
- return true;
209
+ if (descriptor && !descriptor.configurable && !descriptor.writable && !descriptor.set) return true;
239
210
  const ah = target.__ajaxHooker;
240
211
  if (ah && ah.proxyProps && prop in ah.proxyProps) {
241
212
  const pDescriptor = ah.proxyProps[prop];
@@ -257,11 +228,7 @@ export const ajaxHooker = function () {
257
228
  proxyEvents: {},
258
229
  });
259
230
  xhr.addEventListener("readystatechange", (e) => {
260
- if (
261
- ah.proxyXhr.readyState === 4 &&
262
- ah.request &&
263
- typeof ah.request.response === "function"
264
- ) {
231
+ if (ah.proxyXhr.readyState === 4 && ah.request && typeof ah.request.response === "function") {
265
232
  const response = {
266
233
  finalUrl: ah.proxyXhr.responseURL,
267
234
  status: ah.proxyXhr.status,
@@ -284,18 +251,16 @@ export const ajaxHooker = function () {
284
251
  }
285
252
  );
286
253
  }
287
- ah.resThenable = new AHRequest(ah.request)
288
- .waitForResponseKeys(response)
289
- .then(() => {
290
- for (const key of xhrResponses) {
291
- ah.proxyProps[key] = {
292
- get: () => {
293
- if (!(key in response)) response[key] = tempValues[key];
294
- return response[key];
295
- },
296
- };
297
- }
298
- });
254
+ ah.resThenable = new AHRequest(ah.request).waitForResponseKeys(response).then(() => {
255
+ for (const key of xhrResponses) {
256
+ ah.proxyProps[key] = {
257
+ get: () => {
258
+ if (!(key in response)) response[key] = tempValues[key];
259
+ return response[key];
260
+ },
261
+ };
262
+ }
263
+ });
299
264
  }
300
265
  ah.dispatchEvent(e);
301
266
  });
@@ -308,13 +273,7 @@ export const ajaxHooker = function () {
308
273
  set: (val) => ah.addEvent(onEvt, val),
309
274
  };
310
275
  }
311
- for (const method of [
312
- "setRequestHeader",
313
- "addEventListener",
314
- "removeEventListener",
315
- "open",
316
- "send",
317
- ]) {
276
+ for (const method of ["setRequestHeader", "addEventListener", "removeEventListener", "open", "send"]) {
318
277
  ah.proxyProps[method] = { value: ah[method] };
319
278
  }
320
279
  }
@@ -323,8 +282,7 @@ export const ajaxHooker = function () {
323
282
  if (type.startsWith("on")) {
324
283
  this.proxyEvents[type] = typeof event === "function" ? event : null;
325
284
  } else {
326
- if (typeof event === "object" && event !== null)
327
- event = event.handleEvent;
285
+ if (typeof event === "object" && event !== null) event = event.handleEvent;
328
286
  if (typeof event !== "function") return;
329
287
  this.proxyEvents[type] = this.proxyEvents[type] || new Set();
330
288
  this.proxyEvents[type].add(event);
@@ -334,8 +292,7 @@ export const ajaxHooker = function () {
334
292
  if (type.startsWith("on")) {
335
293
  this.proxyEvents[type] = null;
336
294
  } else {
337
- if (typeof event === "object" && event !== null)
338
- event = event.handleEvent;
295
+ if (typeof event === "object" && event !== null) event = event.handleEvent;
339
296
  this.proxyEvents[type] && this.proxyEvents[type].delete(event);
340
297
  }
341
298
  }
@@ -346,9 +303,7 @@ export const ajaxHooker = function () {
346
303
  defineProp(e, "srcElement", () => this.proxyXhr);
347
304
  this.proxyEvents[e.type] &&
348
305
  this.proxyEvents[e.type].forEach((fn) => {
349
- this.resThenable.then(
350
- () => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e)
351
- );
306
+ this.resThenable.then(() => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e));
352
307
  });
353
308
  if (e.ajaxHooker_isStopped) return;
354
309
  const onEvent = this.proxyEvents["on" + e.type];
@@ -358,8 +313,7 @@ export const ajaxHooker = function () {
358
313
  this.originalXhr.setRequestHeader(header, value);
359
314
  if (!this.request) return;
360
315
  const headers = this.request.headers;
361
- headers[header] =
362
- header in headers ? `${headers[header]}, ${value}` : value;
316
+ headers[header] = header in headers ? `${headers[header]}, ${value}` : value;
363
317
  }
364
318
  addEventListener(...args) {
365
319
  if (xhrAsyncEvents.includes(args[0])) {
@@ -388,13 +342,7 @@ export const ajaxHooker = function () {
388
342
  };
389
343
  this.openArgs = args;
390
344
  this.resThenable = new SyncThenable();
391
- [
392
- "responseURL",
393
- "readyState",
394
- "status",
395
- "statusText",
396
- ...xhrResponses,
397
- ].forEach((key) => {
345
+ ["responseURL", "readyState", "status", "statusText", ...xhrResponses].forEach((key) => {
398
346
  delete this.proxyProps[key];
399
347
  });
400
348
  return this.originalXhr.open(method, url, async, ...args);
@@ -431,15 +379,12 @@ export const ajaxHooker = function () {
431
379
  }
432
380
  function fakeXHR() {
433
381
  const xhr = new winAh.realXHR();
434
- if ("__ajaxHooker" in xhr)
435
- console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
382
+ if ("__ajaxHooker" in xhr) console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
436
383
  xhr.__ajaxHooker = new XhrHooker(xhr);
437
384
  return xhr.__ajaxHooker.proxyXhr;
438
385
  }
439
386
  fakeXHR.prototype = win.XMLHttpRequest.prototype;
440
- Object.keys(win.XMLHttpRequest).forEach(
441
- (key) => (fakeXHR[key] = win.XMLHttpRequest[key])
442
- );
387
+ Object.keys(win.XMLHttpRequest).forEach((key) => (fakeXHR[key] = win.XMLHttpRequest[key]));
443
388
  function fakeFetch(url, options = {}) {
444
389
  if (!url) return winAh.realFetch.call(win, url, options);
445
390
  return new Promise(async (resolve, reject) => {
@@ -505,18 +450,22 @@ export const ajaxHooker = function () {
505
450
  status: res.status,
506
451
  responseHeaders: parseHeaders(res.headers),
507
452
  };
508
- fetchResponses.forEach(
509
- (key) =>
510
- (res[key] = function () {
511
- if (key in response) return Promise.resolve(response[key]);
512
- return resProto[key].call(this).then((val) => {
513
- response[key] = val;
514
- return req
515
- .waitForResponseKeys(response)
516
- .then(() => (key in response ? response[key] : val));
517
- });
518
- })
519
- );
453
+ if (res.ok) {
454
+ fetchResponses.forEach(
455
+ (key) =>
456
+ (res[key] = function () {
457
+ if (key in response) return Promise.resolve(response[key]);
458
+ return resProto[key].call(this).then((val) => {
459
+ response[key] = val;
460
+ return req
461
+ .waitForResponseKeys(response)
462
+ .then(() => (key in response ? response[key] : val));
463
+ });
464
+ })
465
+ );
466
+ } else {
467
+ catchError(request.response, response);
468
+ }
520
469
  }
521
470
  resolve(res);
522
471
  }, reject);
@@ -538,8 +487,7 @@ export const ajaxHooker = function () {
538
487
  realFetchClone: resProto.clone,
539
488
  hookInsts: new Set(),
540
489
  };
541
- if (winAh.version !== version)
542
- console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
490
+ if (winAh.version !== version) console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
543
491
  win.XMLHttpRequest = winAh.fakeXHR;
544
492
  win.fetch = winAh.fakeFetch;
545
493
  resProto.clone = winAh.fakeFetchClone;
@@ -547,37 +495,25 @@ export const ajaxHooker = function () {
547
495
  // 针对头条、抖音 secsdk.umd.js 的兼容性处理
548
496
  class AHFunction extends Function {
549
497
  call(thisArg, ...args) {
550
- if (
551
- thisArg &&
552
- thisArg.__ajaxHooker &&
553
- thisArg.__ajaxHooker.proxyXhr === thisArg
554
- ) {
498
+ if (thisArg && thisArg.__ajaxHooker && thisArg.__ajaxHooker.proxyXhr === thisArg) {
555
499
  thisArg = thisArg.__ajaxHooker.originalXhr;
556
500
  }
557
501
  return Reflect.apply(this, thisArg, args);
558
502
  }
559
503
  apply(thisArg, args) {
560
- if (
561
- thisArg &&
562
- thisArg.__ajaxHooker &&
563
- thisArg.__ajaxHooker.proxyXhr === thisArg
564
- ) {
504
+ if (thisArg && thisArg.__ajaxHooker && thisArg.__ajaxHooker.proxyXhr === thisArg) {
565
505
  thisArg = thisArg.__ajaxHooker.originalXhr;
566
506
  }
567
507
  return Reflect.apply(this, thisArg, args || []);
568
508
  }
569
509
  }
570
510
  function hookSecsdk(csrf) {
571
- Object.setPrototypeOf(
572
- csrf.nativeXMLHttpRequestSetRequestHeader,
573
- AHFunction.prototype
574
- );
511
+ Object.setPrototypeOf(csrf.nativeXMLHttpRequestSetRequestHeader, AHFunction.prototype);
575
512
  Object.setPrototypeOf(csrf.nativeXMLHttpRequestOpen, AHFunction.prototype);
576
513
  Object.setPrototypeOf(csrf.nativeXMLHttpRequestSend, AHFunction.prototype);
577
514
  }
578
515
  if (win.secsdk) {
579
- if (win.secsdk.csrf && win.secsdk.csrf.nativeXMLHttpRequestOpen)
580
- hookSecsdk(win.secsdk.csrf);
516
+ if (win.secsdk.csrf && win.secsdk.csrf.nativeXMLHttpRequestOpen) hookSecsdk(win.secsdk.csrf);
581
517
  } else {
582
518
  defineProp(win, "secsdk", emptyFn, (secsdk) => {
583
519
  delete win.secsdk;
@@ -7,4 +7,8 @@ export type WindowApiOption = {
7
7
  globalThis?: typeof globalThis | Window;
8
8
  self?: Window & typeof globalThis;
9
9
  top: Window;
10
+ setTimeout: Window["setTimeout"];
11
+ setInterval: Window["setInterval"];
12
+ clearTimeout: Window["clearTimeout"];
13
+ clearInterval: Window["clearInterval"];
10
14
  };