@emmvish/stable-request 1.7.3 → 1.8.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.
Files changed (59) hide show
  1. package/README.md +457 -0
  2. package/dist/core/stable-api-gateway.d.ts +2 -2
  3. package/dist/core/stable-api-gateway.d.ts.map +1 -1
  4. package/dist/core/stable-api-gateway.js +58 -4
  5. package/dist/core/stable-api-gateway.js.map +1 -1
  6. package/dist/core/stable-request.d.ts +2 -2
  7. package/dist/core/stable-request.d.ts.map +1 -1
  8. package/dist/core/stable-request.js +35 -5
  9. package/dist/core/stable-request.js.map +1 -1
  10. package/dist/core/stable-workflow.d.ts.map +1 -1
  11. package/dist/core/stable-workflow.js +23 -8
  12. package/dist/core/stable-workflow.js.map +1 -1
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/types/index.d.ts +258 -0
  18. package/dist/types/index.d.ts.map +1 -1
  19. package/dist/utilities/cache-manager.d.ts +19 -0
  20. package/dist/utilities/cache-manager.d.ts.map +1 -1
  21. package/dist/utilities/cache-manager.js +38 -2
  22. package/dist/utilities/cache-manager.js.map +1 -1
  23. package/dist/utilities/circuit-breaker.d.ts +22 -0
  24. package/dist/utilities/circuit-breaker.d.ts.map +1 -1
  25. package/dist/utilities/circuit-breaker.js +65 -1
  26. package/dist/utilities/circuit-breaker.js.map +1 -1
  27. package/dist/utilities/concurrency-limiter.d.ts +26 -0
  28. package/dist/utilities/concurrency-limiter.d.ts.map +1 -1
  29. package/dist/utilities/concurrency-limiter.js +74 -4
  30. package/dist/utilities/concurrency-limiter.js.map +1 -1
  31. package/dist/utilities/execute-branch-workflow.d.ts.map +1 -1
  32. package/dist/utilities/execute-branch-workflow.js +115 -19
  33. package/dist/utilities/execute-branch-workflow.js.map +1 -1
  34. package/dist/utilities/execute-concurrently.d.ts.map +1 -1
  35. package/dist/utilities/execute-concurrently.js +5 -6
  36. package/dist/utilities/execute-concurrently.js.map +1 -1
  37. package/dist/utilities/execute-non-linear-workflow.d.ts.map +1 -1
  38. package/dist/utilities/execute-non-linear-workflow.js +47 -3
  39. package/dist/utilities/execute-non-linear-workflow.js.map +1 -1
  40. package/dist/utilities/execute-phase.d.ts +1 -1
  41. package/dist/utilities/execute-phase.d.ts.map +1 -1
  42. package/dist/utilities/execute-phase.js +45 -17
  43. package/dist/utilities/execute-phase.js.map +1 -1
  44. package/dist/utilities/execute-sequentially.d.ts.map +1 -1
  45. package/dist/utilities/execute-sequentially.js +5 -6
  46. package/dist/utilities/execute-sequentially.js.map +1 -1
  47. package/dist/utilities/index.d.ts +4 -3
  48. package/dist/utilities/index.d.ts.map +1 -1
  49. package/dist/utilities/index.js +4 -3
  50. package/dist/utilities/index.js.map +1 -1
  51. package/dist/utilities/metrics-aggregator.d.ts +51 -0
  52. package/dist/utilities/metrics-aggregator.d.ts.map +1 -0
  53. package/dist/utilities/metrics-aggregator.js +311 -0
  54. package/dist/utilities/metrics-aggregator.js.map +1 -0
  55. package/dist/utilities/rate-limiter.d.ts +19 -0
  56. package/dist/utilities/rate-limiter.d.ts.map +1 -1
  57. package/dist/utilities/rate-limiter.js +56 -3
  58. package/dist/utilities/rate-limiter.js.map +1 -1
  59. package/package.json +1 -1
package/README.md CHANGED
@@ -16,6 +16,11 @@ A production-grade HTTP Workflow Execution Engine for Node.js that transforms un
16
16
  - [Circuit Breaker Pattern](#circuit-breaker-pattern)
17
17
  - [Response Caching](#response-caching)
18
18
  - [Rate Limiting and Concurrency Control](#rate-limiting-and-concurrency-control)
19
+ - [Metrics and Observability](#metrics-and-observability)
20
+ - [Request-Level Metrics](#request-level-metrics)
21
+ - [API Gateway Metrics](#api-gateway-metrics)
22
+ - [Workflow Metrics](#workflow-metrics)
23
+ - [MetricsAggregator Utility](#metricsaggregator-utility)
19
24
  - [Workflow Execution Patterns](#workflow-execution-patterns)
20
25
  - [Sequential and Concurrent Phases](#sequential-and-concurrent-phases)
21
26
  - [Mixed Execution Mode](#mixed-execution-mode)
@@ -383,6 +388,336 @@ console.log(state);
383
388
  // { availableTokens: 1000, queueLength: 0, maxRequests: 1000, windowMs: 3600000 }
384
389
  ```
385
390
 
391
+ ## Metrics and Observability
392
+
393
+ `@emmvish/stable-request` provides comprehensive metrics at every level of execution, from individual requests to complete workflows. All metrics are automatically computed and included in results.
394
+
395
+ ### Request-Level Metrics
396
+
397
+ Every `stableRequest` call returns detailed metrics about the request execution:
398
+
399
+ ```typescript
400
+ import { stableRequest } from '@emmvish/stable-request';
401
+
402
+ const result = await stableRequest({
403
+ reqData: {
404
+ hostname: 'api.example.com',
405
+ path: '/users/123'
406
+ },
407
+ resReq: true,
408
+ attempts: 3,
409
+ wait: 1000,
410
+ logAllErrors: true
411
+ });
412
+
413
+ // Access request metrics
414
+ console.log('Request Result:', {
415
+ success: result.success, // true/false
416
+ data: result.data, // Response data
417
+ error: result.error, // Error message (if failed)
418
+ errorLogs: result.errorLogs, // All failed attempts
419
+ successfulAttempts: result.successfulAttempts, // All successful attempts
420
+ metrics: {
421
+ totalAttempts: result.metrics.totalAttempts, // 3
422
+ successfulAttempts: result.metrics.successfulAttempts, // 1
423
+ failedAttempts: result.metrics.failedAttempts, // 2
424
+ totalExecutionTime: result.metrics.totalExecutionTime, // ms
425
+ averageAttemptTime: result.metrics.averageAttemptTime, // ms
426
+ infrastructureMetrics: {
427
+ circuitBreaker: result.metrics.infrastructureMetrics?.circuitBreaker,
428
+ cache: result.metrics.infrastructureMetrics?.cache
429
+ }
430
+ }
431
+ });
432
+
433
+ // Error logs provide detailed attempt information
434
+ result.errorLogs?.forEach(log => {
435
+ console.log({
436
+ attempt: log.attempt, // "1/3"
437
+ timestamp: log.timestamp,
438
+ error: log.error,
439
+ statusCode: log.statusCode,
440
+ type: log.type, // "HTTP_ERROR" | "INVALID_CONTENT"
441
+ isRetryable: log.isRetryable,
442
+ executionTime: log.executionTime
443
+ });
444
+ });
445
+
446
+ // Successful attempts show what worked
447
+ result.successfulAttempts?.forEach(attempt => {
448
+ console.log({
449
+ attempt: attempt.attempt, // "3/3"
450
+ timestamp: attempt.timestamp,
451
+ executionTime: attempt.executionTime,
452
+ data: attempt.data,
453
+ statusCode: attempt.statusCode
454
+ });
455
+ });
456
+ ```
457
+
458
+ **STABLE_REQUEST_RESULT Structure:**
459
+ - `success`: Boolean indicating if request succeeded
460
+ - `data`: Response data (if `resReq: true`)
461
+ - `error`: Error message (if request failed)
462
+ - `errorLogs`: Array of all failed attempt details
463
+ - `successfulAttempts`: Array of all successful attempt details
464
+ - `metrics`: Computed execution metrics and infrastructure statistics
465
+
466
+ ### API Gateway Metrics
467
+
468
+ `stableApiGateway` provides aggregated metrics for batch requests:
469
+
470
+ ```typescript
471
+ import { stableApiGateway } from '@emmvish/stable-request';
472
+
473
+ const requests = [
474
+ { id: 'user-1', groupId: 'users', requestOptions: { reqData: { path: '/users/1' }, resReq: true } },
475
+ { id: 'user-2', groupId: 'users', requestOptions: { reqData: { path: '/users/2' }, resReq: true } },
476
+ { id: 'order-1', groupId: 'orders', requestOptions: { reqData: { path: '/orders/1' }, resReq: true } },
477
+ { id: 'product-1', requestOptions: { reqData: { path: '/products/1' }, resReq: true } }
478
+ ];
479
+
480
+ const results = await stableApiGateway(requests, {
481
+ concurrentExecution: true,
482
+ commonRequestData: { hostname: 'api.example.com' },
483
+ commonAttempts: 3,
484
+ circuitBreaker: { failureThresholdPercentage: 50, minimumRequests: 5 },
485
+ rateLimit: { maxRequests: 100, windowMs: 60000 },
486
+ maxConcurrentRequests: 5
487
+ });
488
+
489
+ // Gateway-level metrics
490
+ console.log('Gateway Metrics:', {
491
+ totalRequests: results.metrics.totalRequests, // 4
492
+ successfulRequests: results.metrics.successfulRequests, // 3
493
+ failedRequests: results.metrics.failedRequests, // 1
494
+ successRate: results.metrics.successRate, // 75%
495
+ failureRate: results.metrics.failureRate // 25%
496
+ });
497
+
498
+ // Request group metrics
499
+ results.metrics.requestGroups?.forEach(group => {
500
+ console.log(`Group ${group.groupId}:`, {
501
+ totalRequests: group.totalRequests,
502
+ successfulRequests: group.successfulRequests,
503
+ failedRequests: group.failedRequests,
504
+ successRate: group.successRate, // %
505
+ failureRate: group.failureRate, // %
506
+ requestIds: group.requestIds // Array of request IDs
507
+ });
508
+ });
509
+
510
+ // Infrastructure metrics (when utilities are used)
511
+ if (results.metrics.infrastructureMetrics) {
512
+ const infra = results.metrics.infrastructureMetrics;
513
+
514
+ // Circuit Breaker metrics
515
+ if (infra.circuitBreaker) {
516
+ console.log('Circuit Breaker:', {
517
+ state: infra.circuitBreaker.state, // CLOSED | OPEN | HALF_OPEN
518
+ isHealthy: infra.circuitBreaker.isHealthy,
519
+ totalRequests: infra.circuitBreaker.totalRequests,
520
+ failurePercentage: infra.circuitBreaker.failurePercentage,
521
+ openCount: infra.circuitBreaker.openCount,
522
+ recoveryAttempts: infra.circuitBreaker.recoveryAttempts
523
+ });
524
+ }
525
+
526
+ // Cache metrics
527
+ if (infra.cache) {
528
+ console.log('Cache:', {
529
+ hitRate: infra.cache.hitRate, // %
530
+ currentSize: infra.cache.currentSize,
531
+ networkRequestsSaved: infra.cache.networkRequestsSaved,
532
+ cacheEfficiency: infra.cache.cacheEfficiency // %
533
+ });
534
+ }
535
+
536
+ // Rate Limiter metrics
537
+ if (infra.rateLimiter) {
538
+ console.log('Rate Limiter:', {
539
+ throttledRequests: infra.rateLimiter.throttledRequests,
540
+ throttleRate: infra.rateLimiter.throttleRate, // %
541
+ peakRequestRate: infra.rateLimiter.peakRequestRate
542
+ });
543
+ }
544
+
545
+ // Concurrency Limiter metrics
546
+ if (infra.concurrencyLimiter) {
547
+ console.log('Concurrency:', {
548
+ peakConcurrency: infra.concurrencyLimiter.peakConcurrency,
549
+ utilizationPercentage: infra.concurrencyLimiter.utilizationPercentage,
550
+ averageQueueWaitTime: infra.concurrencyLimiter.averageQueueWaitTime
551
+ });
552
+ }
553
+ }
554
+ ```
555
+
556
+ ### Workflow Metrics
557
+
558
+ `stableWorkflow` provides end-to-end metrics for complex orchestrations:
559
+
560
+ ```typescript
561
+ import { stableWorkflow, PHASE_DECISION_ACTIONS } from '@emmvish/stable-request';
562
+
563
+ const phases = [
564
+ {
565
+ id: 'fetch-users',
566
+ requests: [/* ... */]
567
+ },
568
+ {
569
+ id: 'process-data',
570
+ concurrent: true,
571
+ requests: [/* ... */]
572
+ },
573
+ {
574
+ id: 'store-results',
575
+ requests: [/* ... */]
576
+ }
577
+ ];
578
+
579
+ const result = await stableWorkflow(phases, {
580
+ workflowId: 'data-processing-pipeline',
581
+ enableMixedExecution: true,
582
+ commonRequestData: { hostname: 'api.example.com' },
583
+ logPhaseResults: true
584
+ });
585
+
586
+ // Workflow-level metrics
587
+ console.log('Workflow Metrics:', {
588
+ workflowId: result.metrics.workflowId,
589
+ success: result.metrics.success,
590
+ executionTime: result.metrics.executionTime, // Total time in ms
591
+
592
+ // Phase statistics
593
+ totalPhases: result.metrics.totalPhases,
594
+ completedPhases: result.metrics.completedPhases,
595
+ skippedPhases: result.metrics.skippedPhases,
596
+ failedPhases: result.metrics.failedPhases,
597
+ phaseCompletionRate: result.metrics.phaseCompletionRate, // %
598
+ averagePhaseExecutionTime: result.metrics.averagePhaseExecutionTime, // ms
599
+
600
+ // Request statistics
601
+ totalRequests: result.metrics.totalRequests,
602
+ successfulRequests: result.metrics.successfulRequests,
603
+ failedRequests: result.metrics.failedRequests,
604
+ requestSuccessRate: result.metrics.requestSuccessRate, // %
605
+ requestFailureRate: result.metrics.requestFailureRate, // %
606
+
607
+ // Performance
608
+ throughput: result.metrics.throughput, // requests/second
609
+ totalPhaseReplays: result.metrics.totalPhaseReplays,
610
+ totalPhaseSkips: result.metrics.totalPhaseSkips,
611
+
612
+ // Branch metrics (if using branch execution)
613
+ totalBranches: result.metrics.totalBranches,
614
+ completedBranches: result.metrics.completedBranches,
615
+ failedBranches: result.metrics.failedBranches,
616
+ branchSuccessRate: result.metrics.branchSuccessRate // %
617
+ });
618
+
619
+ // Request group metrics aggregated across entire workflow
620
+ result.requestGroupMetrics?.forEach(group => {
621
+ console.log(`Request Group ${group.groupId}:`, {
622
+ totalRequests: group.totalRequests,
623
+ successRate: group.successRate, // %
624
+ requestIds: group.requestIds
625
+ });
626
+ });
627
+
628
+ // Per-phase metrics
629
+ result.phases.forEach(phase => {
630
+ console.log(`Phase ${phase.phaseId}:`, {
631
+ executionTime: phase.metrics?.executionTime,
632
+ totalRequests: phase.metrics?.totalRequests,
633
+ successfulRequests: phase.metrics?.successfulRequests,
634
+ requestSuccessRate: phase.metrics?.requestSuccessRate, // %
635
+ hasDecision: phase.metrics?.hasDecision,
636
+ decisionAction: phase.metrics?.decisionAction // CONTINUE | JUMP | REPLAY | etc.
637
+ });
638
+ });
639
+
640
+ // Branch metrics (for branched workflows)
641
+ result.branches?.forEach(branch => {
642
+ console.log(`Branch ${branch.branchId}:`, {
643
+ success: branch.metrics?.success,
644
+ executionTime: branch.metrics?.executionTime,
645
+ totalPhases: branch.metrics?.totalPhases,
646
+ completedPhases: branch.metrics?.completedPhases,
647
+ totalRequests: branch.metrics?.totalRequests,
648
+ requestSuccessRate: branch.metrics?.requestSuccessRate // %
649
+ });
650
+ });
651
+ ```
652
+
653
+ ### MetricsAggregator Utility
654
+
655
+ For custom metrics extraction and analysis:
656
+
657
+ ```typescript
658
+ import { MetricsAggregator } from '@emmvish/stable-request';
659
+
660
+ // Extract workflow metrics
661
+ const workflowMetrics = MetricsAggregator.extractWorkflowMetrics(workflowResult);
662
+
663
+ // Extract phase metrics
664
+ const phaseMetrics = MetricsAggregator.extractPhaseMetrics(phaseResult);
665
+
666
+ // Extract branch metrics
667
+ const branchMetrics = MetricsAggregator.extractBranchMetrics(branchResult);
668
+
669
+ // Extract request group metrics
670
+ const requestGroups = MetricsAggregator.extractRequestGroupMetrics(responses);
671
+
672
+ // Extract individual request metrics
673
+ const requestMetrics = MetricsAggregator.extractRequestMetrics(responses);
674
+
675
+ // Extract circuit breaker metrics
676
+ const cbMetrics = MetricsAggregator.extractCircuitBreakerMetrics(circuitBreaker);
677
+
678
+ // Extract cache metrics
679
+ const cacheMetrics = MetricsAggregator.extractCacheMetrics(cacheManager);
680
+
681
+ // Extract rate limiter metrics
682
+ const rateLimiterMetrics = MetricsAggregator.extractRateLimiterMetrics(rateLimiter);
683
+
684
+ // Extract concurrency limiter metrics
685
+ const concurrencyMetrics = MetricsAggregator.extractConcurrencyLimiterMetrics(limiter);
686
+
687
+ // Aggregate all system metrics
688
+ const systemMetrics = MetricsAggregator.aggregateSystemMetrics(
689
+ workflowResult,
690
+ circuitBreaker,
691
+ cacheManager,
692
+ rateLimiter,
693
+ concurrencyLimiter
694
+ );
695
+
696
+ console.log('Complete System View:', {
697
+ workflow: systemMetrics.workflow,
698
+ phases: systemMetrics.phases,
699
+ branches: systemMetrics.branches,
700
+ requestGroups: systemMetrics.requestGroups,
701
+ requests: systemMetrics.requests,
702
+ circuitBreaker: systemMetrics.circuitBreaker,
703
+ cache: systemMetrics.cache,
704
+ rateLimiter: systemMetrics.rateLimiter,
705
+ concurrencyLimiter: systemMetrics.concurrencyLimiter
706
+ });
707
+ ```
708
+
709
+ **Available Metrics Types:**
710
+ - `WorkflowMetrics`: Complete workflow statistics
711
+ - `BranchMetrics`: Branch execution metrics
712
+ - `PhaseMetrics`: Individual phase metrics
713
+ - `RequestGroupMetrics`: Grouped request statistics
714
+ - `RequestMetrics`: Individual request metrics
715
+ - `CircuitBreakerDashboardMetrics`: Circuit breaker state and performance
716
+ - `CacheDashboardMetrics`: Cache hit rates and efficiency
717
+ - `RateLimiterDashboardMetrics`: Throttling and rate limit statistics
718
+ - `ConcurrencyLimiterDashboardMetrics`: Concurrency and queue metrics
719
+ - `SystemMetrics`: Complete system-wide aggregation
720
+
386
721
  ## Workflow Execution Patterns
387
722
 
388
723
  ### Sequential and Concurrent Phases
@@ -586,6 +921,85 @@ phaseDecisionHook: async ({
586
921
  }
587
922
  ```
588
923
 
924
+ ### Dynamic Phase and Branch Addition
925
+
926
+ Dynamically add phases or branches during workflow execution based on runtime conditions:
927
+
928
+ **Adding Phases Dynamically**:
929
+ ```typescript
930
+ const phases = [
931
+ {
932
+ id: 'initial-phase',
933
+ requests: [...],
934
+ phaseDecisionHook: async ({ phaseResult }) => {
935
+ const needsExtraProcessing = phaseResult.responses[0]?.data?.requiresValidation;
936
+
937
+ if (needsExtraProcessing) {
938
+ return {
939
+ action: PHASE_DECISION_ACTIONS.CONTINUE,
940
+ addPhases: [
941
+ {
942
+ id: 'validation-phase',
943
+ requests: [{ id: 'validate', requestOptions: { reqData: { path: '/validate' }, resReq: true } }]
944
+ }
945
+ ]
946
+ };
947
+ }
948
+ return { action: PHASE_DECISION_ACTIONS.CONTINUE };
949
+ }
950
+ }
951
+ ];
952
+
953
+ await stableWorkflow(phases, {
954
+ enableNonLinearExecution: true,
955
+ commonRequestData: { hostname: 'api.example.com' }
956
+ });
957
+ ```
958
+
959
+ **Adding Branches Dynamically**:
960
+ ```typescript
961
+ const branches = [
962
+ {
963
+ id: 'main-branch',
964
+ phases: [...],
965
+ branchDecisionHook: async ({ branchResults }) => {
966
+ const requiresAudit = branchResults.some(p => p.responses[0]?.data?.flagged);
967
+
968
+ if (requiresAudit) {
969
+ return {
970
+ action: PHASE_DECISION_ACTIONS.CONTINUE,
971
+ addBranches: [
972
+ {
973
+ id: 'audit-branch',
974
+ phases: [{ id: 'audit', requests: [...] }]
975
+ }
976
+ ]
977
+ };
978
+ }
979
+ return { action: PHASE_DECISION_ACTIONS.CONTINUE };
980
+ }
981
+ }
982
+ ];
983
+
984
+ await stableWorkflow([], {
985
+ enableBranchExecution: true,
986
+ branches,
987
+ commonRequestData: { hostname: 'api.example.com' }
988
+ });
989
+ ```
990
+
991
+ **Extending Current Branch**:
992
+ ```typescript
993
+ branchDecisionHook: async ({ branchResults }) => {
994
+ return {
995
+ action: PHASE_DECISION_ACTIONS.CONTINUE,
996
+ addPhases: [
997
+ { id: 'extra-phase', requests: [...] } // Branch re-executes with new phases
998
+ ]
999
+ };
1000
+ }
1001
+ ```
1002
+
589
1003
  ### Branched Workflows
590
1004
 
591
1005
  Execute multiple independent workflow paths in parallel or sequentially:
@@ -853,6 +1267,49 @@ console.log(sharedBuffer); // Updated with data from workfl
853
1267
  }
854
1268
  ```
855
1269
 
1270
+ **Pre-Phase Execution Hooks**:
1271
+
1272
+ Modify phase configuration before execution:
1273
+
1274
+ ```typescript
1275
+ const phases = [
1276
+ {
1277
+ id: 'data-phase',
1278
+ requests: [...],
1279
+ prePhaseExecutionHook: async ({ phase, sharedBuffer, params }) => {
1280
+ // Dynamically modify phase based on shared state
1281
+ if (sharedBuffer.environment === 'production') {
1282
+ phase.commonConfig = { commonAttempts: 5, commonWait: 2000 };
1283
+ }
1284
+ return phase;
1285
+ }
1286
+ }
1287
+ ];
1288
+ ```
1289
+
1290
+ **Pre-Branch Execution Hooks**:
1291
+
1292
+ Modify branch configuration before execution:
1293
+
1294
+ ```typescript
1295
+ const branches = [
1296
+ {
1297
+ id: 'api-branch',
1298
+ phases: [...],
1299
+ preBranchExecutionHook: async ({ branch, sharedBuffer }) => {
1300
+ // Add authentication header dynamically
1301
+ branch.commonConfig = {
1302
+ ...branch.commonConfig,
1303
+ commonRequestData: {
1304
+ headers: { 'Authorization': `Bearer ${sharedBuffer.token}` }
1305
+ }
1306
+ };
1307
+ return branch;
1308
+ }
1309
+ }
1310
+ ];
1311
+ ```
1312
+
856
1313
  ### State Persistence and Recovery
857
1314
 
858
1315
  Persist workflow state to external storage for recovery, distributed coordination, and long-running workflows.
@@ -1,3 +1,3 @@
1
- import { API_GATEWAY_OPTIONS, API_GATEWAY_REQUEST } from '../types/index.js';
2
- export declare function stableApiGateway<RequestDataType = any, ResponseDataType = any>(requests?: API_GATEWAY_REQUEST<RequestDataType, ResponseDataType>[], options?: API_GATEWAY_OPTIONS<RequestDataType, ResponseDataType>): Promise<import("../types/index.js").API_GATEWAY_RESPONSE<ResponseDataType>[]>;
1
+ import { API_GATEWAY_OPTIONS, API_GATEWAY_REQUEST, API_GATEWAY_RESULT } from '../types/index.js';
2
+ export declare function stableApiGateway<RequestDataType = any, ResponseDataType = any>(requests?: API_GATEWAY_REQUEST<RequestDataType, ResponseDataType>[], options?: API_GATEWAY_OPTIONS<RequestDataType, ResponseDataType>): Promise<API_GATEWAY_RESULT<ResponseDataType>>;
3
3
  //# sourceMappingURL=stable-api-gateway.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stable-api-gateway.d.ts","sourceRoot":"","sources":["../../src/core/stable-api-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,EACnB,mBAAmB,EAGtB,MAAM,mBAAmB,CAAC;AAO3B,wBAAsB,gBAAgB,CAAC,eAAe,GAAG,GAAG,EAAE,gBAAgB,GAAG,GAAG,EAChF,QAAQ,GAAE,mBAAmB,CAAC,eAAe,EAAE,gBAAgB,CAAC,EAAO,EACvE,OAAO,GAAE,mBAAmB,CAAC,eAAe,EAAE,gBAAgB,CAAM,iFA8BvE"}
1
+ {"version":3,"file":"stable-api-gateway.d.ts","sourceRoot":"","sources":["../../src/core/stable-api-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,EACnB,mBAAmB,EAEnB,kBAAkB,EAOrB,MAAM,mBAAmB,CAAC;AAY3B,wBAAsB,gBAAgB,CAAC,eAAe,GAAG,GAAG,EAAE,gBAAgB,GAAG,GAAG,EAChF,QAAQ,GAAE,mBAAmB,CAAC,eAAe,EAAE,gBAAgB,CAAC,EAAO,EACvE,OAAO,GAAE,mBAAmB,CAAC,eAAe,EAAE,gBAAgB,CAAM,GACrE,OAAO,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC,CA6F/C"}
@@ -1,8 +1,20 @@
1
- import { executeConcurrently, executeSequentially, extractCommonRequestConfigOptions as extractCommonOptions } from '../utilities/index.js';
1
+ import { executeConcurrently, executeSequentially, extractCommonRequestConfigOptions as extractCommonOptions, MetricsAggregator } from '../utilities/index.js';
2
+ import { CircuitBreaker, getGlobalCircuitBreaker } from '../utilities/circuit-breaker.js';
3
+ import { getGlobalCacheManager } from '../utilities/cache-manager.js';
4
+ import { getGlobalRateLimiter } from '../utilities/rate-limiter.js';
5
+ import { getGlobalConcurrencyLimiter } from '../utilities/concurrency-limiter.js';
2
6
  export async function stableApiGateway(requests = [], options = {}) {
3
7
  const { concurrentExecution = true, stopOnFirstError = false, requestGroups = [], maxConcurrentRequests, rateLimit, circuitBreaker, } = options;
4
8
  if (!Array.isArray(requests) || requests.length === 0) {
5
- return [];
9
+ const emptyResult = [];
10
+ emptyResult.metrics = {
11
+ totalRequests: 0,
12
+ successfulRequests: 0,
13
+ failedRequests: 0,
14
+ successRate: 0,
15
+ failureRate: 0
16
+ };
17
+ return emptyResult;
6
18
  }
7
19
  const requestExecutionOptions = {
8
20
  stopOnFirstError,
@@ -13,11 +25,53 @@ export async function stableApiGateway(requests = [], options = {}) {
13
25
  ...(circuitBreaker !== undefined && { circuitBreaker }),
14
26
  ...extractCommonOptions(options)
15
27
  };
28
+ let responses;
16
29
  if (concurrentExecution) {
17
- return executeConcurrently(requests, requestExecutionOptions);
30
+ responses = await executeConcurrently(requests, requestExecutionOptions);
18
31
  }
19
32
  else {
20
- return executeSequentially(requests, requestExecutionOptions);
33
+ responses = await executeSequentially(requests, requestExecutionOptions);
21
34
  }
35
+ const successfulRequests = responses.filter(r => r.success).length;
36
+ const failedRequests = responses.filter(r => !r.success).length;
37
+ const totalRequests = responses.length;
38
+ const result = responses;
39
+ result.metrics = {
40
+ totalRequests,
41
+ successfulRequests,
42
+ failedRequests,
43
+ successRate: totalRequests > 0 ? (successfulRequests / totalRequests) * 100 : 0,
44
+ failureRate: totalRequests > 0 ? (failedRequests / totalRequests) * 100 : 0,
45
+ requestGroups: MetricsAggregator.extractRequestGroupMetrics(responses)
46
+ };
47
+ const infrastructureMetrics = {};
48
+ if (circuitBreaker) {
49
+ const cb = circuitBreaker instanceof CircuitBreaker ? circuitBreaker : getGlobalCircuitBreaker();
50
+ if (cb) {
51
+ infrastructureMetrics.circuitBreaker = MetricsAggregator.extractCircuitBreakerMetrics(cb);
52
+ }
53
+ }
54
+ if (options.commonCache) {
55
+ const cache = getGlobalCacheManager();
56
+ if (cache) {
57
+ infrastructureMetrics.cache = MetricsAggregator.extractCacheMetrics(cache);
58
+ }
59
+ }
60
+ if (rateLimit) {
61
+ const rateLimiter = getGlobalRateLimiter();
62
+ if (rateLimiter) {
63
+ infrastructureMetrics.rateLimiter = MetricsAggregator.extractRateLimiterMetrics(rateLimiter);
64
+ }
65
+ }
66
+ if (maxConcurrentRequests) {
67
+ const concurrencyLimiter = getGlobalConcurrencyLimiter();
68
+ if (concurrencyLimiter) {
69
+ infrastructureMetrics.concurrencyLimiter = MetricsAggregator.extractConcurrencyLimiterMetrics(concurrencyLimiter);
70
+ }
71
+ }
72
+ if (Object.keys(infrastructureMetrics).length > 0) {
73
+ result.metrics.infrastructureMetrics = infrastructureMetrics;
74
+ }
75
+ return result;
22
76
  }
23
77
  //# sourceMappingURL=stable-api-gateway.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stable-api-gateway.js","sourceRoot":"","sources":["../../src/core/stable-api-gateway.ts"],"names":[],"mappings":"AAMA,OAAO,EACH,mBAAmB,EACnB,mBAAmB,EACnB,iCAAiC,IAAI,oBAAoB,EAC5D,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAClC,WAAqE,EAAE,EACvE,UAAkE,EAAE;IAEpE,MAAM,EACF,mBAAmB,GAAG,IAAI,EAC1B,gBAAgB,GAAG,KAAK,EACxB,aAAa,GAAG,EAAE,EAClB,qBAAqB,EACrB,SAAS,EACT,cAAc,GACjB,GAAG,OAAO,CAAC;IAEZ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,uBAAuB,GAAgF;QACzG,gBAAgB;QAChB,aAAa;QACb,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,GAAG,CAAC,qBAAqB,KAAK,SAAS,IAAI,EAAE,qBAAqB,EAAE,CAAC;QACrE,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;QAC7C,GAAG,CAAC,cAAc,KAAK,SAAS,IAAI,EAAE,cAAc,EAAE,CAAC;QACvD,GAAG,oBAAoB,CAAoC,OAAO,CAAC;KACtE,CAAA;IAED,IAAI,mBAAmB,EAAE,CAAC;QACtB,OAAO,mBAAmB,CAAoC,QAAQ,EAAE,uBAAkG,CAAC,CAAC;IAChL,CAAC;SAAM,CAAC;QACJ,OAAO,mBAAmB,CAAoC,QAAQ,EAAE,uBAAkG,CAAC,CAAC;IAChL,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"stable-api-gateway.js","sourceRoot":"","sources":["../../src/core/stable-api-gateway.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { STABLE_REQUEST } from '../types/index.js';
2
- export declare function stableRequest<RequestDataType = any, ResponseDataType = any>(options: STABLE_REQUEST<RequestDataType, ResponseDataType>): Promise<ResponseDataType | boolean>;
1
+ import { STABLE_REQUEST, STABLE_REQUEST_RESULT } from '../types/index.js';
2
+ export declare function stableRequest<RequestDataType = any, ResponseDataType = any>(options: STABLE_REQUEST<RequestDataType, ResponseDataType>): Promise<STABLE_REQUEST_RESULT<ResponseDataType>>;
3
3
  //# sourceMappingURL=stable-request.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stable-request.d.ts","sourceRoot":"","sources":["../../src/core/stable-request.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,cAAc,EAEf,MAAM,mBAAmB,CAAC;AAe3B,wBAAsB,aAAa,CAAC,eAAe,GAAG,GAAG,EAAE,gBAAgB,GAAG,GAAG,EAC/E,OAAO,EAAE,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC,GACzD,OAAO,CAAC,gBAAgB,GAAG,OAAO,CAAC,CAmVrC"}
1
+ {"version":3,"file":"stable-request.d.ts","sourceRoot":"","sources":["../../src/core/stable-request.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,cAAc,EACd,qBAAqB,EAEtB,MAAM,mBAAmB,CAAC;AAkB3B,wBAAsB,aAAa,CAAC,eAAe,GAAG,GAAG,EAAE,gBAAgB,GAAG,GAAG,EAC/E,OAAO,EAAE,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC,GACzD,OAAO,CAAC,qBAAqB,CAAC,gBAAgB,CAAC,CAAC,CAqXlD"}