vigor-fetch 3.1.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -206,6 +206,36 @@ class VigorRetry extends VigorStatus {
206
206
  backoff: (config) => new VigorRetryAlgorithmsBackoff(config),
207
207
  custom: (config) => new VigorRetryAlgorithmsCustom(config)
208
208
  };
209
+ _createTimelineHandler(timeline) {
210
+ return (action, content) => {
211
+ timeline.push({
212
+ action: action,
213
+ content: content,
214
+ time: Date.now()
215
+ });
216
+ };
217
+ }
218
+ _createInterceptorHandler(ctx, addTimeline) {
219
+ return async (interceptorType, api) => {
220
+ const interceptorsConfig = ctx["stats"]["interceptors"];
221
+ const interceptors = interceptorsConfig[interceptorType];
222
+ addTimeline("INTERCEPTOR_LOOP_STARTED", {
223
+ interceptorType: interceptorType,
224
+ interceptors,
225
+ });
226
+ const startTime = performance.now();
227
+ for (const func of interceptors) {
228
+ const scopedApi = api(interceptorType, func);
229
+ await func(ctx, scopedApi);
230
+ }
231
+ const endTime = performance.now();
232
+ addTimeline("INTERCEPTOR_LOOP_ENDED", {
233
+ interceptorType: interceptorType,
234
+ interceptors,
235
+ took: endTime - startTime
236
+ });
237
+ };
238
+ }
209
239
  target(func) { return this._next({ target: func }); }
210
240
  settings(func) {
211
241
  if (typeof func === 'function') {
@@ -236,11 +266,18 @@ class VigorRetry extends VigorStatus {
236
266
  controller: VigorDefault,
237
267
  timeline: timeline,
238
268
  stats,
269
+ flag: {
270
+ broke: false,
271
+ overwritten: false,
272
+ restarted: false
273
+ }
239
274
  };
240
- const throwError = (error) => {
241
- ctx.timeline.push({ action: "throwError called", content: error });
242
- throw error;
243
- };
275
+ const addTimeline = this._createTimelineHandler(ctx.timeline);
276
+ const handleInterceptor = this._createInterceptorHandler(ctx, addTimeline);
277
+ addTimeline("PROCESS_HANDLING", {
278
+ type: "REQUEST_START",
279
+ data: {}
280
+ });
244
281
  try {
245
282
  if (typeof stats.target !== 'function')
246
283
  throw new VigorRetryError("INVALID_TARGET", {
@@ -254,23 +291,48 @@ class VigorRetry extends VigorStatus {
254
291
  });
255
292
  while (ctx.attempt < stats.settings.attempt) {
256
293
  ctx.attempt++;
257
- ctx.timeline.push({ action: "increased attempt", content: ctx.attempt });
258
- let broke = false;
259
- const breakRetry = (error) => {
260
- ctx.timeline.push({ action: "breakRetry called", content: error });
261
- broke = true;
262
- throw error;
263
- };
294
+ addTimeline("ATTEMPT_INCREASED", {
295
+ attempt: ctx.attempt
296
+ });
264
297
  try {
265
- ctx.timeline.push({ action: "process request_once handling", content: ctx.attempt });
298
+ addTimeline("PROCESS_HANDLING", {
299
+ type: "RETRY_START",
300
+ data: {}
301
+ });
266
302
  const controller = new AbortController();
267
303
  const timeoutController = new AbortController();
268
304
  const signal = AbortSignal.any([controller.signal, timeoutController.signal, ...stats.abortSignals]);
269
- const abort = (err) => controller.abort(err);
270
- ctx.timeline.push({ action: "interceptor handling: before", content: stats.interceptors.before });
271
- for (const func of stats.interceptors.before) {
272
- await func(ctx, { throwError, breakRetry, abort });
273
- }
305
+ await handleInterceptor("before", (interceptorType, func) => ({
306
+ abort: (error) => {
307
+ addTimeline("INTERCEPTOR_API_CALLED", {
308
+ interceptorType,
309
+ interceptor: func,
310
+ method: "abort",
311
+ args: [error]
312
+ });
313
+ controller.abort(error);
314
+ throw error;
315
+ },
316
+ breakRetry: (error) => {
317
+ addTimeline("INTERCEPTOR_API_CALLED", {
318
+ interceptorType,
319
+ interceptor: func,
320
+ method: "breakRetry",
321
+ args: [error]
322
+ });
323
+ ctx.flag.broke = true;
324
+ throw error;
325
+ },
326
+ throwError: (error) => {
327
+ addTimeline("INTERCEPTOR_API_CALLED", {
328
+ interceptorType,
329
+ interceptor: func,
330
+ method: "throwError",
331
+ args: [error]
332
+ });
333
+ throw error;
334
+ }
335
+ }));
274
336
  const timeoutTimer = setTimeout(() => {
275
337
  clearTimeout(timeoutTimer);
276
338
  timeoutController.abort(new VigorRetryError("TIMED_OUT", {
@@ -284,6 +346,18 @@ class VigorRetry extends VigorStatus {
284
346
  signal.throwIfAborted();
285
347
  let onAbort;
286
348
  try {
349
+ addTimeline("TARGET_REQUEST_STARTED", {
350
+ target: stats.target
351
+ });
352
+ const abort = (error) => {
353
+ addTimeline("TARGET_API_CALLED", {
354
+ target: stats.target,
355
+ method: "abort"
356
+ });
357
+ controller.abort(error);
358
+ throw error;
359
+ };
360
+ const started = performance.now();
287
361
  ctx.result = await Promise.race([
288
362
  stats.target(ctx, { abort, signal }),
289
363
  new Promise((_, rej) => {
@@ -291,60 +365,134 @@ class VigorRetry extends VigorStatus {
291
365
  signal.addEventListener("abort", onAbort);
292
366
  })
293
367
  ]);
368
+ const endTime = performance.now();
369
+ addTimeline("TARGET_REQUEST_ENDED", {
370
+ target: stats.target,
371
+ took: endTime - started
372
+ });
294
373
  }
295
374
  finally {
296
375
  clearTimeout(timeoutTimer);
297
376
  if (onAbort)
298
377
  signal.removeEventListener("abort", onAbort);
299
378
  }
300
- const setResult = (unk) => {
301
- ctx.timeline.push({ action: "setResult called", content: unk });
302
- ctx.result = unk;
303
- return unk;
304
- };
305
- ctx.timeline.push({ action: "interceptor handling: after", content: stats.interceptors.after });
306
- for (const func of stats.interceptors.after) {
307
- await func(ctx, { setResult, throwError, breakRetry });
308
- }
309
- ctx.timeline.push({ action: "interceptor handling: result", content: stats.interceptors.result });
310
- for (const func of stats.interceptors.result) {
311
- await func(ctx, { setResult, throwError });
312
- }
379
+ await handleInterceptor("after", (interceptorType, func) => ({
380
+ setResult: (unknown) => {
381
+ addTimeline("INTERCEPTOR_API_CALLED", {
382
+ interceptorType,
383
+ interceptor: func,
384
+ method: "setResult",
385
+ args: [unknown]
386
+ });
387
+ ctx.result = unknown;
388
+ return unknown;
389
+ },
390
+ throwError: (error) => {
391
+ addTimeline("INTERCEPTOR_API_CALLED", {
392
+ interceptorType,
393
+ interceptor: func,
394
+ method: "throwError",
395
+ args: [error]
396
+ });
397
+ throw error;
398
+ },
399
+ breakRetry: (error) => {
400
+ addTimeline("INTERCEPTOR_API_CALLED", {
401
+ interceptorType,
402
+ interceptor: func,
403
+ method: "breakRetry",
404
+ args: [error]
405
+ });
406
+ ctx.flag.broke = true;
407
+ throw error;
408
+ },
409
+ }));
410
+ await handleInterceptor("result", (interceptorType, func) => ({
411
+ setResult: (unknown) => {
412
+ addTimeline("INTERCEPTOR_API_CALLED", {
413
+ interceptorType,
414
+ interceptor: func,
415
+ method: "setResult",
416
+ args: [unknown]
417
+ });
418
+ ctx.result = unknown;
419
+ return unknown;
420
+ },
421
+ throwError: (error) => {
422
+ addTimeline("INTERCEPTOR_API_CALLED", {
423
+ interceptorType,
424
+ interceptor: func,
425
+ method: "throwError",
426
+ args: [error]
427
+ });
428
+ throw error;
429
+ },
430
+ }));
313
431
  return ctx.result;
314
432
  }
315
433
  catch (error) {
316
434
  ctx.error = error;
317
- ctx.timeline.push({ action: "process error_once handling", content: error });
318
- if (broke)
435
+ addTimeline("PROCESS_HANDLING", {
436
+ type: "RETRY_ERROR",
437
+ data: {
438
+ error
439
+ }
440
+ });
441
+ if (ctx.flag.broke)
319
442
  throw error;
320
443
  let proceed = true;
321
- const proceedRetry = () => {
322
- ctx.timeline.push({ action: "proceedRetry called", content: true });
323
- return proceed = true;
324
- };
325
- const cancelRetry = () => {
326
- ctx.timeline.push({ action: "cancelRetry called", content: false });
327
- return proceed = false;
328
- };
329
- ctx.timeline.push({ action: "interceptor handling: retryIf", content: stats.interceptors.result });
330
- for (const func of stats.interceptors.retryIf) {
331
- await func(ctx, { proceedRetry, cancelRetry });
332
- }
444
+ await handleInterceptor("retryIf", (interceptorType, func) => ({
445
+ proceedRetry: () => {
446
+ addTimeline("INTERCEPTOR_API_CALLED", {
447
+ interceptorType,
448
+ interceptor: func,
449
+ method: "proceedRetry",
450
+ args: []
451
+ });
452
+ return proceed = true;
453
+ },
454
+ cancelRetry: () => {
455
+ addTimeline("INTERCEPTOR_API_CALLED", {
456
+ interceptorType,
457
+ interceptor: func,
458
+ method: "cancelRetry",
459
+ args: []
460
+ });
461
+ return proceed = false;
462
+ }
463
+ }));
333
464
  if (!proceed)
334
465
  throw error;
335
466
  ctx.delay = VigorDefault;
336
- const setDelay = (num) => {
337
- ctx.timeline.push({ action: "setDelay called", content: num });
338
- return ctx.delay = num;
339
- };
340
- const setAttempt = (num) => {
341
- ctx.timeline.push({ action: "setAttempt called", content: num });
342
- return ctx.attempt = num;
343
- };
344
- ctx.timeline.push({ action: "interceptor handling: onRetry", content: stats.interceptors.onRetry });
345
- for (const func of stats.interceptors.onRetry) {
346
- await func(ctx, { throwError, setDelay, setAttempt });
347
- }
467
+ await handleInterceptor("onRetry", (interceptorType, func) => ({
468
+ throwError: (error) => {
469
+ addTimeline("INTERCEPTOR_API_CALLED", {
470
+ interceptorType,
471
+ interceptor: func,
472
+ method: "throwError",
473
+ args: [error]
474
+ });
475
+ throw error;
476
+ },
477
+ setDelay: (number) => {
478
+ addTimeline("INTERCEPTOR_API_CALLED", {
479
+ interceptorType,
480
+ interceptor: func,
481
+ method: "setDelay",
482
+ args: [number]
483
+ });
484
+ return ctx.delay = number;
485
+ },
486
+ setAttempt: (number) => {
487
+ addTimeline("INTERCEPTOR_API_CALLED", {
488
+ interceptorType,
489
+ interceptor: func,
490
+ method: "setAttempt",
491
+ args: [number]
492
+ });
493
+ return ctx.attempt = number;
494
+ }
495
+ }));
348
496
  if (typeof ctx.delay !== 'number')
349
497
  ctx.delay = stats.algorithm(ctx.attempt) + Math.random() * stats.settings.jitter;
350
498
  const delay = ctx.delay;
@@ -361,26 +509,47 @@ class VigorRetry extends VigorStatus {
361
509
  }
362
510
  catch (error) {
363
511
  ctx.error = error;
364
- let overwritten = false;
365
- const setResult = (unk) => {
366
- ctx.timeline.push({ action: "setResult called", content: unk });
367
- ctx.result = unk;
368
- overwritten = true;
369
- return unk;
370
- };
371
- let restarted = false;
372
- const restart = () => {
373
- ctx.timeline.push({ action: "restart called" });
374
- restarted = true;
375
- };
376
- ctx.timeline.push({ action: "interceptor handling: onError", content: stats.interceptors.onError });
377
- for (const func of stats.interceptors.onError) {
378
- await func(ctx, { setResult, throwError, restart });
379
- }
380
- if (restarted) {
512
+ addTimeline("PROCESS_HANDLING", {
513
+ type: "REQUEST_ERROR",
514
+ data: {
515
+ error
516
+ }
517
+ });
518
+ await handleInterceptor("onError", (interceptorType, func) => ({
519
+ setResult: (unknown) => {
520
+ addTimeline("INTERCEPTOR_API_CALLED", {
521
+ interceptorType,
522
+ interceptor: func,
523
+ method: "setResult",
524
+ args: [unknown]
525
+ });
526
+ ctx.result = unknown;
527
+ ctx.flag.overwritten = true;
528
+ return unknown;
529
+ },
530
+ throwError: (error) => {
531
+ addTimeline("INTERCEPTOR_API_CALLED", {
532
+ interceptorType,
533
+ interceptor: func,
534
+ method: "throwError",
535
+ args: [error]
536
+ });
537
+ throw error;
538
+ },
539
+ restart: () => {
540
+ addTimeline("INTERCEPTOR_API_CALLED", {
541
+ interceptorType,
542
+ interceptor: func,
543
+ method: "restart",
544
+ args: []
545
+ });
546
+ ctx.flag.restarted = true;
547
+ }
548
+ }));
549
+ if (ctx.flag.restarted) {
381
550
  return await this.request(stats, ctx.timeline);
382
551
  }
383
- if (overwritten)
552
+ if (ctx.flag.overwritten)
384
553
  return ctx.result;
385
554
  if (stats.settings.default !== VigorDefault)
386
555
  return stats.settings.default;
@@ -405,7 +574,6 @@ class VigorParseStrategies extends VigorStatus {
405
574
  funcs: []
406
575
  };
407
576
  super(config, base, (c) => new VigorParseStrategies(c));
408
- this._config.funcs.push(this.ParseAutoAlgorithms.contentType);
409
577
  }
410
578
  ParseAutoHeaders = [
411
579
  { header: "application/json", regExp: /application\/(.+\+)?json(.+\+)?/i, method: (res) => res.json() },
@@ -504,6 +672,36 @@ class VigorParse extends VigorStatus {
504
672
  };
505
673
  super(config, base, (c) => new VigorParse(c));
506
674
  }
675
+ _createTimelineHandler(timeline) {
676
+ return (action, content) => {
677
+ timeline.push({
678
+ action: action,
679
+ content: content,
680
+ time: Date.now()
681
+ });
682
+ };
683
+ }
684
+ _createInterceptorHandler(ctx, addTimeline) {
685
+ return async (interceptorType, api) => {
686
+ const interceptorsConfig = ctx["stats"]["interceptors"];
687
+ const interceptors = interceptorsConfig[interceptorType];
688
+ addTimeline("INTERCEPTOR_LOOP_STARTED", {
689
+ interceptorType: interceptorType,
690
+ interceptors,
691
+ });
692
+ const startTime = performance.now();
693
+ for (const func of interceptors) {
694
+ const scopedApi = api(interceptorType, func);
695
+ await func(ctx, scopedApi);
696
+ }
697
+ const endTime = performance.now();
698
+ addTimeline("INTERCEPTOR_LOOP_ENDED", {
699
+ interceptorType: interceptorType,
700
+ interceptors,
701
+ took: endTime - startTime
702
+ });
703
+ };
704
+ }
507
705
  target(response) { return this._next({ target: response }); }
508
706
  settings(func) {
509
707
  if (typeof func === 'function') {
@@ -532,11 +730,16 @@ class VigorParse extends VigorStatus {
532
730
  response: target,
533
731
  result: VigorDefault,
534
732
  error: VigorDefault,
733
+ flag: {
734
+ overwritten: false
735
+ }
535
736
  };
536
- const throwError = (err) => {
537
- ctx.timeline.push({ action: "throwError called", content: err });
538
- throw err;
539
- };
737
+ const addTimeline = this._createTimelineHandler(ctx.timeline);
738
+ const handleInterceptor = this._createInterceptorHandler(ctx, addTimeline);
739
+ addTimeline("PROCESS_HANDLING", {
740
+ type: "REQUEST_START",
741
+ data: {}
742
+ });
540
743
  try {
541
744
  if (target === VigorDefault)
542
745
  throw new VigorParseError("INVALID_TARGET", {
@@ -547,10 +750,17 @@ class VigorParse extends VigorStatus {
547
750
  },
548
751
  context: ctx
549
752
  });
550
- ctx.timeline.push({ action: "interceptor handling: before", content: stats.interceptors.before });
551
- for (const func of stats.interceptors.before) {
552
- await func(ctx, { throwError });
553
- }
753
+ await handleInterceptor("before", (interceptorType, func) => ({
754
+ throwError: (error) => {
755
+ addTimeline("INTERCEPTOR_API_CALLED", {
756
+ interceptorType,
757
+ interceptor: func,
758
+ method: "throwError",
759
+ args: [error]
760
+ });
761
+ throw error;
762
+ },
763
+ }));
554
764
  if (stats.settings.raw) {
555
765
  ctx.result = ctx.response;
556
766
  }
@@ -579,35 +789,81 @@ class VigorParse extends VigorStatus {
579
789
  context: ctx
580
790
  });
581
791
  }
582
- const setResult = (unk) => {
583
- ctx.timeline.push({ action: "setResult called", content: unk });
584
- ctx.result = unk;
585
- return unk;
586
- };
587
- ctx.timeline.push({ action: "interceptor handling: after", content: stats.interceptors.after });
588
- for (const func of stats.interceptors.after) {
589
- await func(ctx, { setResult, throwError });
590
- }
591
- ctx.timeline.push({ action: "interceptor handling: result", content: stats.interceptors.result });
592
- for (const func of stats.interceptors.result) {
593
- await func(ctx, { setResult, throwError });
594
- }
792
+ await handleInterceptor("after", (interceptorType, func) => ({
793
+ setResult: (unknown) => {
794
+ addTimeline("INTERCEPTOR_API_CALLED", {
795
+ interceptorType,
796
+ interceptor: func,
797
+ method: "setResult",
798
+ args: [unknown]
799
+ });
800
+ ctx.result = unknown;
801
+ return unknown;
802
+ },
803
+ throwError: (error) => {
804
+ addTimeline("INTERCEPTOR_API_CALLED", {
805
+ interceptorType,
806
+ interceptor: func,
807
+ method: "throwError",
808
+ args: [error]
809
+ });
810
+ throw error;
811
+ },
812
+ }));
813
+ await handleInterceptor("result", (interceptorType, func) => ({
814
+ setResult: (unknown) => {
815
+ addTimeline("INTERCEPTOR_API_CALLED", {
816
+ interceptorType,
817
+ interceptor: func,
818
+ method: "setResult",
819
+ args: [unknown]
820
+ });
821
+ ctx.result = unknown;
822
+ return unknown;
823
+ },
824
+ throwError: (error) => {
825
+ addTimeline("INTERCEPTOR_API_CALLED", {
826
+ interceptorType,
827
+ interceptor: func,
828
+ method: "throwError",
829
+ args: [error]
830
+ });
831
+ throw error;
832
+ },
833
+ }));
595
834
  return ctx.result;
596
835
  }
597
836
  catch (error) {
598
837
  ctx.error = error;
599
- let overwritten = false;
600
- const setResult = (unk) => {
601
- ctx.timeline.push({ action: "setResult called", content: unk });
602
- ctx.result = unk;
603
- overwritten = true;
604
- return unk;
605
- };
606
- ctx.timeline.push({ action: "interceptor handling: onError", content: stats.interceptors.onError });
607
- for (const func of stats.interceptors.onError) {
608
- await func(ctx, { setResult, throwError });
609
- }
610
- if (overwritten)
838
+ addTimeline("PROCESS_HANDLING", {
839
+ type: "REQUEST_ERROR",
840
+ data: {
841
+ error
842
+ }
843
+ });
844
+ await handleInterceptor("onError", (interceptorType, func) => ({
845
+ setResult: (unknown) => {
846
+ addTimeline("INTERCEPTOR_API_CALLED", {
847
+ interceptorType,
848
+ interceptor: func,
849
+ method: "setResult",
850
+ args: [unknown]
851
+ });
852
+ ctx.result = unknown;
853
+ ctx.flag.overwritten = true;
854
+ return unknown;
855
+ },
856
+ throwError: (error) => {
857
+ addTimeline("INTERCEPTOR_API_CALLED", {
858
+ interceptorType,
859
+ interceptor: func,
860
+ method: "throwError",
861
+ args: [error]
862
+ });
863
+ throw error;
864
+ },
865
+ }));
866
+ if (ctx.flag.overwritten)
611
867
  return ctx.result;
612
868
  if (stats.settings.default !== VigorDefault)
613
869
  return stats.settings.default;
@@ -661,6 +917,36 @@ class VigorFetch extends VigorStatus {
661
917
  };
662
918
  super(config, base, (c) => new VigorFetch(c));
663
919
  }
920
+ _createTimelineHandler(timeline) {
921
+ return (action, content) => {
922
+ timeline.push({
923
+ action: action,
924
+ content: content,
925
+ time: Date.now()
926
+ });
927
+ };
928
+ }
929
+ _createInterceptorHandler(ctx, addTimeline) {
930
+ return async (interceptorType, api) => {
931
+ const interceptorsConfig = ctx["stats"]["interceptors"];
932
+ const interceptors = interceptorsConfig[interceptorType];
933
+ addTimeline("INTERCEPTOR_LOOP_STARTED", {
934
+ interceptorType: interceptorType,
935
+ interceptors,
936
+ });
937
+ const startTime = performance.now();
938
+ for (const func of interceptors) {
939
+ const scopedApi = api(interceptorType, func);
940
+ await func(ctx, scopedApi);
941
+ }
942
+ const endTime = performance.now();
943
+ addTimeline("INTERCEPTOR_LOOP_ENDED", {
944
+ interceptorType: interceptorType,
945
+ interceptors,
946
+ took: endTime - startTime
947
+ });
948
+ };
949
+ }
664
950
  _stringifyList(unkList) {
665
951
  return unkList
666
952
  .filter(unk => unk !== null && unk !== undefined)
@@ -670,6 +956,7 @@ class VigorFetch extends VigorStatus {
670
956
  return String(unk);
671
957
  });
672
958
  }
959
+ method(str) { return this._next({ method: str }); }
673
960
  origin(...strs) { return this._next({ origin: this._stringifyList(strs.flat()) }); }
674
961
  path(...strs) { return this._next({ path: this._stringifyList(strs.flat()) }); }
675
962
  query(...strs) { return this._next({ query: strs.flat() }); }
@@ -777,11 +1064,17 @@ class VigorFetch extends VigorStatus {
777
1064
  error: VigorDefault,
778
1065
  timeline: timeline,
779
1066
  stats,
1067
+ flag: {
1068
+ overwritten: false,
1069
+ restarted: false
1070
+ }
780
1071
  };
781
- const throwError = (err) => {
782
- ctx.timeline.push({ action: "throwError called", content: err });
783
- throw err;
784
- };
1072
+ const addTimeline = this._createTimelineHandler(ctx.timeline);
1073
+ const handleInterceptor = this._createInterceptorHandler(ctx, addTimeline);
1074
+ addTimeline("PROCESS_HANDLING", {
1075
+ type: "REQUEST_START",
1076
+ data: {}
1077
+ });
785
1078
  try {
786
1079
  try {
787
1080
  new URL(stats.origin[0]);
@@ -796,13 +1089,18 @@ class VigorFetch extends VigorStatus {
796
1089
  });
797
1090
  }
798
1091
  ctx.href = this._buildUrl(stats.origin, stats.path, stats.query, stats.hash);
1092
+ addTimeline("BUILT_URL", {
1093
+ url: ctx.href
1094
+ });
799
1095
  const { headers, body, ...others } = stats.options;
1096
+ const hasBody = body !== VigorDefault &&
1097
+ body !== undefined;
1098
+ const method = stats.method || (hasBody ? 'POST' : 'GET');
800
1099
  ctx.options = {
801
1100
  ...others,
1101
+ method: method,
802
1102
  headers: {}
803
1103
  };
804
- const hasBody = body !== VigorDefault &&
805
- body !== undefined;
806
1104
  if (hasBody) {
807
1105
  const normalized = this._normalizeOptions(body);
808
1106
  if (normalized.body !== undefined) {
@@ -811,19 +1109,9 @@ class VigorFetch extends VigorStatus {
811
1109
  Object.assign(ctx.options.headers, normalized.headers);
812
1110
  }
813
1111
  Object.assign(ctx.options.headers, headers);
814
- ctx.timeline.push({ action: "options set", content: ctx.options });
815
- const setOptions = (unk) => {
816
- ctx.timeline.push({ action: "setOptions called", content: unk });
817
- return ctx.options = unk;
818
- };
819
- const setHeaders = (unk) => {
820
- ctx.timeline.push({ action: "setHeaders called", content: unk });
821
- return ctx.options.headers = unk;
822
- };
823
- const setBody = (unk) => {
824
- ctx.timeline.push({ action: "setBody called", content: unk });
825
- return ctx.options.body = unk;
826
- };
1112
+ addTimeline("SET_OPTIONS", {
1113
+ options: ctx.options
1114
+ });
827
1115
  const fetchTask = async (ctx2, { abort, signal }) => {
828
1116
  ctx.options.signal = signal;
829
1117
  const result = await fetch(ctx.href, ctx.options);
@@ -882,55 +1170,167 @@ class VigorFetch extends VigorStatus {
882
1170
  }
883
1171
  }
884
1172
  };
885
- stats.retryConfig.interceptors.after.unshift(throwStatus);
886
- stats.retryConfig.interceptors.retryIf.unshift(handleBlacklist);
887
- stats.retryConfig.interceptors.onRetry.unshift(handleRatelimit);
1173
+ stats.retryConfig.interceptors.after = [throwStatus, ...stats.retryConfig.interceptors.after];
1174
+ stats.retryConfig.interceptors.retryIf = [handleBlacklist, ...stats.retryConfig.interceptors.retryIf];
1175
+ stats.retryConfig.interceptors.onRetry = [handleRatelimit, ...stats.retryConfig.interceptors.onRetry];
888
1176
  const retryEngine = new VigorRetry(stats.retryConfig)
889
1177
  .target(fetchTask);
890
1178
  const parseEngine = new VigorParse(stats.parseConfig);
891
- ctx.timeline.push({ action: "interceptor handling: before", content: stats.interceptors.before });
892
- for (const func of stats.interceptors.before) {
893
- await func(ctx, { throwError, setOptions, setHeaders, setBody });
894
- }
895
- ctx.response = await retryEngine.request(undefined, timeline);
896
- ctx.result = await parseEngine.target(ctx.response).request(undefined, timeline);
897
- const setResult = (unk) => {
898
- ctx.timeline.push({ action: "setResult called", content: unk });
899
- ctx.result = unk;
900
- return unk;
901
- };
902
- ctx.timeline.push({ action: "interceptor handling: after", content: stats.interceptors.after });
903
- for (const func of stats.interceptors.after) {
904
- await func(ctx, { setResult, throwError });
905
- }
906
- ctx.timeline.push({ action: "interceptor handling: result", content: stats.interceptors.result });
907
- for (const func of stats.interceptors.result) {
908
- await func(ctx, { setResult, throwError });
909
- }
1179
+ addTimeline("ENGINE_CREATED", {
1180
+ retryEngine,
1181
+ parseEngine
1182
+ });
1183
+ await handleInterceptor("before", (interceptorType, func) => ({
1184
+ throwError: (error) => {
1185
+ addTimeline("INTERCEPTOR_API_CALLED", {
1186
+ interceptorType,
1187
+ interceptor: func,
1188
+ method: "throwError",
1189
+ args: [error]
1190
+ });
1191
+ throw error;
1192
+ },
1193
+ setOptions: (unknown) => {
1194
+ addTimeline("INTERCEPTOR_API_CALLED", {
1195
+ interceptorType,
1196
+ interceptor: func,
1197
+ method: "setOptions",
1198
+ args: [unknown]
1199
+ });
1200
+ return ctx.options = unknown;
1201
+ },
1202
+ setHeaders: (unknown) => {
1203
+ addTimeline("INTERCEPTOR_API_CALLED", {
1204
+ interceptorType,
1205
+ interceptor: func,
1206
+ method: "setHeaders",
1207
+ args: [unknown]
1208
+ });
1209
+ return ctx.options.headers = unknown;
1210
+ },
1211
+ setBody: (unknown) => {
1212
+ addTimeline("INTERCEPTOR_API_CALLED", {
1213
+ interceptorType,
1214
+ interceptor: func,
1215
+ method: "setBody",
1216
+ args: [unknown]
1217
+ });
1218
+ return ctx.options.body = unknown;
1219
+ }
1220
+ }));
1221
+ addTimeline("RETRY_STARTED", {
1222
+ engine: retryEngine
1223
+ });
1224
+ const retryStart = performance.now();
1225
+ const retryTimeline = [];
1226
+ ctx.response = await retryEngine.request(undefined, retryTimeline);
1227
+ const retryEnd = performance.now();
1228
+ addTimeline("RETRY_ENDED", {
1229
+ engine: retryEngine,
1230
+ timeline: retryTimeline,
1231
+ took: retryEnd - retryStart,
1232
+ response: ctx.response
1233
+ });
1234
+ addTimeline("PARSE_STARTED", {
1235
+ engine: parseEngine
1236
+ });
1237
+ const parseStart = performance.now();
1238
+ const parseTimeline = [];
1239
+ ctx.result = await parseEngine.target(ctx.response).request(undefined, parseTimeline);
1240
+ const parseEnd = performance.now();
1241
+ addTimeline("PARSE_ENDED", {
1242
+ engine: parseEngine,
1243
+ timeline: parseTimeline,
1244
+ took: parseEnd - parseStart,
1245
+ result: ctx.result
1246
+ });
1247
+ await handleInterceptor("after", (interceptorType, func) => ({
1248
+ setResult: (unknown) => {
1249
+ addTimeline("INTERCEPTOR_API_CALLED", {
1250
+ interceptorType,
1251
+ interceptor: func,
1252
+ method: "setResult",
1253
+ args: [unknown]
1254
+ });
1255
+ ctx.result = unknown;
1256
+ return unknown;
1257
+ },
1258
+ throwError: (error) => {
1259
+ addTimeline("INTERCEPTOR_API_CALLED", {
1260
+ interceptorType,
1261
+ interceptor: func,
1262
+ method: "throwError",
1263
+ args: [error]
1264
+ });
1265
+ throw error;
1266
+ },
1267
+ }));
1268
+ await handleInterceptor("result", (interceptorType, func) => ({
1269
+ setResult: (unknown) => {
1270
+ addTimeline("INTERCEPTOR_API_CALLED", {
1271
+ interceptorType,
1272
+ interceptor: func,
1273
+ method: "setResult",
1274
+ args: [unknown]
1275
+ });
1276
+ ctx.result = unknown;
1277
+ return unknown;
1278
+ },
1279
+ throwError: (error) => {
1280
+ addTimeline("INTERCEPTOR_API_CALLED", {
1281
+ interceptorType,
1282
+ interceptor: func,
1283
+ method: "throwError",
1284
+ args: [error]
1285
+ });
1286
+ throw error;
1287
+ },
1288
+ }));
910
1289
  return ctx.result;
911
1290
  }
912
1291
  catch (error) {
913
1292
  ctx.error = error;
914
- let overwritten = false;
915
- const setResult = (unk) => {
916
- ctx.timeline.push({ action: "setResult called", content: unk });
917
- ctx.result = unk;
918
- overwritten = true;
919
- return unk;
920
- };
921
- let restarted = false;
922
- const restart = () => {
923
- ctx.timeline.push({ action: "restart called" });
924
- restarted = true;
925
- };
926
- ctx.timeline.push({ action: "interceptor handling: onError", content: stats.interceptors.onError });
927
- for (const func of stats.interceptors.onError) {
928
- await func(ctx, { setResult, throwError, restart });
929
- }
930
- if (restarted) {
931
- return await this.request(stats, timeline);
1293
+ addTimeline("PROCESS_HANDLING", {
1294
+ type: "REQUEST_ERROR",
1295
+ data: {
1296
+ error
1297
+ }
1298
+ });
1299
+ await handleInterceptor("onError", (interceptorType, func) => ({
1300
+ setResult: (unknown) => {
1301
+ addTimeline("INTERCEPTOR_API_CALLED", {
1302
+ interceptorType,
1303
+ interceptor: func,
1304
+ method: "setResult",
1305
+ args: [unknown]
1306
+ });
1307
+ ctx.result = unknown;
1308
+ ctx.flag.overwritten = true;
1309
+ return unknown;
1310
+ },
1311
+ throwError: (error) => {
1312
+ addTimeline("INTERCEPTOR_API_CALLED", {
1313
+ interceptorType,
1314
+ interceptor: func,
1315
+ method: "throwError",
1316
+ args: [error]
1317
+ });
1318
+ throw error;
1319
+ },
1320
+ restart: () => {
1321
+ addTimeline("INTERCEPTOR_API_CALLED", {
1322
+ interceptorType,
1323
+ interceptor: func,
1324
+ method: "restart",
1325
+ args: []
1326
+ });
1327
+ ctx.flag.restarted = true;
1328
+ }
1329
+ }));
1330
+ if (ctx.flag.restarted) {
1331
+ return await this.request(stats, ctx.timeline);
932
1332
  }
933
- if (overwritten)
1333
+ if (ctx.flag.overwritten)
934
1334
  return ctx.result;
935
1335
  if (stats.settings.default !== VigorDefault)
936
1336
  return stats.settings.default;
@@ -973,6 +1373,66 @@ class VigorAll extends VigorStatus {
973
1373
  };
974
1374
  super(config, base, (c) => new VigorAll(c));
975
1375
  }
1376
+ _createTimelineHandler(timeline) {
1377
+ return (action, content) => {
1378
+ timeline.push({
1379
+ action: action,
1380
+ content: content,
1381
+ time: Date.now()
1382
+ });
1383
+ };
1384
+ }
1385
+ _createInterceptorHandler(ctx, addTimeline) {
1386
+ return async (interceptorType, api) => {
1387
+ const interceptorsConfig = ctx["stats"]["interceptors"];
1388
+ const interceptors = interceptorsConfig[interceptorType];
1389
+ addTimeline("INTERCEPTOR_LOOP_STARTED", {
1390
+ interceptorType: interceptorType,
1391
+ interceptors,
1392
+ });
1393
+ const startTime = performance.now();
1394
+ for (const func of interceptors) {
1395
+ const scopedApi = api(interceptorType, func);
1396
+ await func(ctx, scopedApi);
1397
+ }
1398
+ const endTime = performance.now();
1399
+ addTimeline("INTERCEPTOR_LOOP_ENDED", {
1400
+ interceptorType: interceptorType,
1401
+ interceptors,
1402
+ took: endTime - startTime
1403
+ });
1404
+ };
1405
+ }
1406
+ _createEachTimelineHandler(timeline) {
1407
+ return (action, content) => {
1408
+ timeline.push({
1409
+ action: action,
1410
+ content: content,
1411
+ time: Date.now()
1412
+ });
1413
+ };
1414
+ }
1415
+ _createEachInterceptorHandler(ctx, addEachTimeline) {
1416
+ return async (interceptorType, api) => {
1417
+ const interceptorsConfig = ctx["stats"]["interceptors"];
1418
+ const interceptors = interceptorsConfig[interceptorType];
1419
+ addEachTimeline("INTERCEPTOR_LOOP_STARTED", {
1420
+ interceptorType: interceptorType,
1421
+ interceptors,
1422
+ });
1423
+ const startTime = performance.now();
1424
+ for (const func of interceptors) {
1425
+ const scopedApi = api(interceptorType, func);
1426
+ await func(ctx, scopedApi);
1427
+ }
1428
+ const endTime = performance.now();
1429
+ addEachTimeline("INTERCEPTOR_LOOP_ENDED", {
1430
+ interceptorType: interceptorType,
1431
+ interceptors,
1432
+ took: endTime - startTime
1433
+ });
1434
+ };
1435
+ }
976
1436
  target(...funcs) { return this._next({ target: funcs.flat() }); }
977
1437
  settings(func) {
978
1438
  if (typeof func === 'function') {
@@ -994,56 +1454,108 @@ class VigorAll extends VigorStatus {
994
1454
  stats,
995
1455
  root,
996
1456
  target: task,
997
- semaphore
998
- };
999
- const throwError = (err) => {
1000
- ctx.timeline.push({ action: "throwError called", content: err });
1001
- throw err;
1457
+ semaphore,
1458
+ flag: {
1459
+ overwritten: false
1460
+ }
1002
1461
  };
1462
+ const addEachTimeline = this._createEachTimelineHandler(ctx.timeline);
1463
+ const handleEachInterceptor = this._createEachInterceptorHandler(ctx, addEachTimeline);
1464
+ addEachTimeline("PROCESS_HANDLING", {
1465
+ type: "TASK_START",
1466
+ data: {}
1467
+ });
1003
1468
  try {
1004
1469
  try {
1005
1470
  await semaphore.acquire();
1006
- ctx.timeline.push({ action: "task acquired", content: ctx.target });
1007
- ctx.timeline.push({ action: "interceptor handling: before", content: stats.interceptors.before });
1008
- for (const func of stats.interceptors.before) {
1009
- await func(ctx, { throwError });
1010
- }
1011
- ctx.timeline.push({ action: "task started", content: ctx.target });
1012
- ctx.result = await task(ctx);
1471
+ addEachTimeline("TASK_ACQUIRED", {
1472
+ target: ctx.target
1473
+ });
1474
+ await handleEachInterceptor("before", (interceptorType, func) => ({
1475
+ throwError: (error) => {
1476
+ addEachTimeline("INTERCEPTOR_API_CALLED", {
1477
+ interceptorType,
1478
+ interceptor: func,
1479
+ method: "throwError",
1480
+ args: [error]
1481
+ });
1482
+ throw error;
1483
+ }
1484
+ }));
1485
+ addEachTimeline("TASK_STARTED", {
1486
+ target: ctx.target
1487
+ });
1488
+ const startTime = performance.now();
1489
+ ctx.result = await ctx.target(ctx);
1490
+ const endTime = performance.now();
1491
+ addEachTimeline("TASK_ENDED", {
1492
+ target: ctx.target,
1493
+ took: endTime - startTime
1494
+ });
1495
+ await handleEachInterceptor("after", (interceptorType, func) => ({
1496
+ setResult: (unknown) => {
1497
+ addEachTimeline("INTERCEPTOR_API_CALLED", {
1498
+ interceptorType,
1499
+ interceptor: func,
1500
+ method: "setResult",
1501
+ args: [unknown]
1502
+ });
1503
+ ctx.result = unknown;
1504
+ return unknown;
1505
+ },
1506
+ throwError: (error) => {
1507
+ addEachTimeline("INTERCEPTOR_API_CALLED", {
1508
+ interceptorType,
1509
+ interceptor: func,
1510
+ method: "throwError",
1511
+ args: [error]
1512
+ });
1513
+ throw error;
1514
+ }
1515
+ }));
1013
1516
  }
1014
1517
  finally {
1015
- ctx.timeline.push({ action: "task ended", content: ctx.target });
1016
- const setResult = (unk) => {
1017
- ctx.timeline.push({ action: "setResult called", content: unk });
1018
- ctx.result = unk;
1019
- return unk;
1020
- };
1021
- ctx.timeline.push({ action: "interceptor handling: after", content: stats.interceptors.after });
1022
- for (const func of stats.interceptors.after) {
1023
- await func(ctx, { setResult, throwError });
1024
- }
1025
1518
  semaphore.release();
1026
- ctx.timeline.push({ action: "task released", content: ctx.target });
1027
- return ctx.result;
1519
+ addEachTimeline("TASK_RELEASED", {
1520
+ target: ctx.target
1521
+ });
1028
1522
  }
1029
1523
  }
1030
1524
  catch (error) {
1031
1525
  ctx.error = error;
1032
- let overwritten = false;
1033
- const setResult = (unk) => {
1034
- ctx.timeline.push({ action: "setResult called", content: unk });
1035
- ctx.result = unk;
1036
- overwritten = true;
1037
- return unk;
1038
- };
1039
- ctx.timeline.push({ action: "interceptor handling: onError", content: stats.interceptors.onError });
1040
- for (const func of stats.interceptors.onError) {
1041
- await func(ctx, { setResult, throwError });
1042
- }
1043
- if (overwritten)
1526
+ addEachTimeline("PROCESS_HANDLING", {
1527
+ type: "TASK_ERROR",
1528
+ data: {
1529
+ error
1530
+ }
1531
+ });
1532
+ await handleEachInterceptor("onError", (interceptorType, func) => ({
1533
+ setResult: (unknown) => {
1534
+ addEachTimeline("INTERCEPTOR_API_CALLED", {
1535
+ interceptorType,
1536
+ interceptor: func,
1537
+ method: "setResult",
1538
+ args: [unknown]
1539
+ });
1540
+ ctx.result = unknown;
1541
+ ctx.flag.overwritten = true;
1542
+ return unknown;
1543
+ },
1544
+ throwError: (error) => {
1545
+ addEachTimeline("INTERCEPTOR_API_CALLED", {
1546
+ interceptorType,
1547
+ interceptor: func,
1548
+ method: "throwError",
1549
+ args: [error]
1550
+ });
1551
+ throw error;
1552
+ },
1553
+ }));
1554
+ if (ctx.flag.overwritten)
1044
1555
  return ctx.result;
1045
1556
  throw error;
1046
1557
  }
1558
+ return ctx.result;
1047
1559
  }
1048
1560
  async request(config, timeline = []) {
1049
1561
  const stats = this._mergeConfig(this._config, config);
@@ -1051,29 +1563,37 @@ class VigorAll extends VigorStatus {
1051
1563
  result: VigorDefault,
1052
1564
  timeline,
1053
1565
  stats,
1054
- queue: new Set()
1566
+ queue: new Set(),
1567
+ active: 0
1055
1568
  };
1569
+ const addTimeline = this._createTimelineHandler(ctx.timeline);
1570
+ const handleInterceptor = this._createInterceptorHandler(ctx, addTimeline);
1571
+ addTimeline("PROCESS_HANDLING", {
1572
+ type: "REQUEST_START",
1573
+ data: {}
1574
+ });
1056
1575
  if (stats.target.length === 0)
1057
1576
  throw new VigorAllError("EMPTY_TARGET", {
1058
1577
  method: "request",
1059
1578
  data: {}
1060
1579
  });
1061
1580
  const waitQueue = [];
1581
+ const acquire = () => {
1582
+ if (ctx.active < stats.settings.concurrency) {
1583
+ ctx.active++;
1584
+ return Promise.resolve();
1585
+ }
1586
+ return new Promise((res) => waitQueue.push(() => { ctx.active++; res(); }));
1587
+ };
1588
+ const release = () => {
1589
+ ctx.active--;
1590
+ if (waitQueue.length > 0) {
1591
+ const next = waitQueue.shift();
1592
+ if (next)
1593
+ next();
1594
+ }
1595
+ };
1062
1596
  for (const task of stats.target) {
1063
- const acquire = () => {
1064
- if (ctx.queue.size < stats.settings.concurrency) {
1065
- return Promise.resolve();
1066
- }
1067
- return new Promise((res) => waitQueue.push(res));
1068
- };
1069
- const release = () => {
1070
- if (waitQueue.length > 0) {
1071
- const next = waitQueue.shift();
1072
- if (next)
1073
- next();
1074
- }
1075
- };
1076
- acquire();
1077
1597
  let promise;
1078
1598
  promise = this.runTask(task, { stats, root: ctx }, { acquire, release }).then(res => {
1079
1599
  ctx.queue.delete(promise);
@@ -1081,23 +1601,40 @@ class VigorAll extends VigorStatus {
1081
1601
  }).catch(err => ({ success: false, value: err }));
1082
1602
  ctx.queue.add(promise);
1083
1603
  }
1604
+ addTimeline("QUEUE_REQUEST_STARTED", {
1605
+ queue: ctx.queue
1606
+ });
1607
+ const startTime = performance.now();
1084
1608
  const raw = await Promise.all(ctx.queue);
1609
+ const endTime = performance.now();
1610
+ addTimeline("QUEUE_REQUEST_ENDED", {
1611
+ queue: ctx.queue,
1612
+ took: endTime - startTime
1613
+ });
1085
1614
  ctx.result = stats.settings.onlySuccess
1086
1615
  ? raw.filter(r => r.success).map(r => r.value)
1087
1616
  : raw.map(r => r.value);
1088
- const setResult = (unk) => {
1089
- ctx.timeline.push({ action: "setResult called", content: unk });
1090
- ctx.result = unk;
1091
- return unk;
1092
- };
1093
- const throwError = (err) => {
1094
- ctx.timeline.push({ action: "throwError called", content: err });
1095
- throw err;
1096
- };
1097
- ctx.timeline.push({ action: "interceptor handling: result", content: stats.interceptors.result });
1098
- for (const func of stats.interceptors.result) {
1099
- await func(ctx, { setResult, throwError });
1100
- }
1617
+ await handleInterceptor("result", (interceptorType, func) => ({
1618
+ setResult: (unknown) => {
1619
+ addTimeline("INTERCEPTOR_API_CALLED", {
1620
+ interceptorType,
1621
+ interceptor: func,
1622
+ method: "setResult",
1623
+ args: [unknown]
1624
+ });
1625
+ ctx.result = unknown;
1626
+ return unknown;
1627
+ },
1628
+ throwError: (error) => {
1629
+ addTimeline("INTERCEPTOR_API_CALLED", {
1630
+ interceptorType,
1631
+ interceptor: func,
1632
+ method: "throwError",
1633
+ args: [error]
1634
+ });
1635
+ throw error;
1636
+ },
1637
+ }));
1101
1638
  return ctx.result;
1102
1639
  }
1103
1640
  }