vigor-fetch 3.0.1 → 3.1.1

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