@aiaiaichain/agent 0.1.5 → 0.1.7

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 (121) hide show
  1. package/dist/api/ExtensionAPI.d.ts +0 -1
  2. package/dist/api/ExtensionAPI.js +3 -7
  3. package/dist/api/Registry.d.ts +0 -1
  4. package/dist/api/Registry.js +54 -57
  5. package/dist/cli.d.ts +0 -1
  6. package/dist/cli.js +684 -685
  7. package/dist/core/AgentDir.d.ts +1 -1
  8. package/dist/core/AgentDir.js +45 -39
  9. package/dist/core/ChainConfig.d.ts +0 -1
  10. package/dist/core/ChainConfig.js +51 -55
  11. package/dist/core/EnvLoader.d.ts +4 -1
  12. package/dist/core/EnvLoader.js +97 -84
  13. package/dist/core/SystemMonitor.d.ts +0 -1
  14. package/dist/core/SystemMonitor.js +72 -85
  15. package/dist/index.d.ts +0 -1
  16. package/dist/index.js +19 -26
  17. package/dist/loader.d.ts +0 -1
  18. package/dist/loader.js +64 -67
  19. package/dist/mcp/entry.d.ts +0 -1
  20. package/dist/mcp/entry.js +3 -6
  21. package/dist/mcp/server.d.ts +0 -1
  22. package/dist/mcp/server.js +152 -156
  23. package/dist/models/CostTracker.d.ts +0 -1
  24. package/dist/models/CostTracker.js +58 -61
  25. package/dist/models/ModelRegistry.d.ts +0 -1
  26. package/dist/models/ModelRegistry.js +195 -155
  27. package/dist/providers/ProviderRegistry.d.ts +0 -1
  28. package/dist/providers/ProviderRegistry.js +33 -36
  29. package/dist/runner/AgentRunner.d.ts +0 -1
  30. package/dist/runner/AgentRunner.js +180 -184
  31. package/dist/runner/ModelClient.d.ts +0 -1
  32. package/dist/runner/ModelClient.js +133 -134
  33. package/dist/runner/SwarmRouter.d.ts +0 -1
  34. package/dist/runner/SwarmRouter.js +18 -22
  35. package/dist/runner/ToolDispatcher.d.ts +0 -1
  36. package/dist/runner/ToolDispatcher.js +30 -33
  37. package/dist/scheduler/AgentScheduler.d.ts +0 -1
  38. package/dist/scheduler/AgentScheduler.js +99 -103
  39. package/dist/session/ContextStore.d.ts +1 -1
  40. package/dist/session/ContextStore.js +76 -78
  41. package/dist/session/GoalManager.d.ts +0 -1
  42. package/dist/session/GoalManager.js +96 -100
  43. package/dist/session/MemoryStore.d.ts +2 -1
  44. package/dist/session/MemoryStore.js +108 -87
  45. package/dist/session/SessionManager.d.ts +5 -4
  46. package/dist/session/SessionManager.js +83 -62
  47. package/dist/session/SessionStore.d.ts +0 -1
  48. package/dist/session/SessionStore.js +112 -116
  49. package/dist/setup/SetupWizard.d.ts +0 -1
  50. package/dist/setup/SetupWizard.js +61 -64
  51. package/dist/tools/CrossTools.d.ts +0 -1
  52. package/dist/tools/CrossTools.js +140 -144
  53. package/dist/tools/GmgnIntegration.d.ts +0 -1
  54. package/dist/tools/GmgnIntegration.js +220 -230
  55. package/dist/tools/MarketSentiment.d.ts +0 -1
  56. package/dist/tools/MarketSentiment.js +213 -195
  57. package/dist/tools/NewsSentiment.d.ts +0 -1
  58. package/dist/tools/NewsSentiment.js +126 -130
  59. package/dist/tools/PriceFeed.d.ts +6 -1
  60. package/dist/tools/PriceFeed.js +201 -133
  61. package/dist/tools/TechnicalAnalysis.d.ts +1 -2
  62. package/dist/tools/TechnicalAnalysis.js +248 -216
  63. package/dist/tools/TechnicalAnalysis.worker.d.ts +25 -0
  64. package/dist/tools/TechnicalAnalysis.worker.js +92 -0
  65. package/dist/tools/TokenCalendar.d.ts +0 -1
  66. package/dist/tools/TokenCalendar.js +63 -68
  67. package/dist/tools/TokenSecurityScanner.d.ts +0 -1
  68. package/dist/tools/TokenSecurityScanner.js +93 -96
  69. package/dist/tools/TransactionSim.d.ts +0 -1
  70. package/dist/tools/TransactionSim.js +65 -71
  71. package/dist/tui/App.d.ts +0 -1
  72. package/dist/tui/App.js +895 -824
  73. package/dist/tui/ModelSelector.d.ts +0 -1
  74. package/dist/tui/ModelSelector.js +46 -49
  75. package/dist/tui/REPL.d.ts +0 -1
  76. package/dist/tui/REPL.js +222 -210
  77. package/dist/tui/Sparkline.d.ts +0 -1
  78. package/dist/tui/Sparkline.js +36 -37
  79. package/dist/tui/StatusBar.d.ts +0 -1
  80. package/dist/tui/StatusBar.js +9 -10
  81. package/dist/tui/ThemePresets.d.ts +0 -1
  82. package/dist/tui/ThemePresets.js +99 -103
  83. package/dist/tui/theme.d.ts +0 -1
  84. package/dist/tui/theme.js +50 -31
  85. package/dist/util/clipboard.d.ts +0 -1
  86. package/dist/util/clipboard.js +16 -20
  87. package/dist/util/commandSuggest.d.ts +0 -1
  88. package/dist/util/commandSuggest.js +34 -38
  89. package/dist/util/confirmation.d.ts +0 -1
  90. package/dist/util/confirmation.js +8 -11
  91. package/dist/util/errorHandler.d.ts +0 -1
  92. package/dist/util/errorHandler.js +20 -23
  93. package/dist/util/errors.d.ts +59 -0
  94. package/dist/util/errors.js +93 -0
  95. package/dist/util/logger.d.ts +0 -1
  96. package/dist/util/logger.js +30 -33
  97. package/dist/util/processManager.d.ts +0 -1
  98. package/dist/util/processManager.js +33 -36
  99. package/dist/util/resilientFetch.d.ts +6 -1
  100. package/dist/util/resilientFetch.js +134 -80
  101. package/dist/util/responseCache.d.ts +0 -1
  102. package/dist/util/responseCache.js +36 -45
  103. package/dist/util/rpc.d.ts +16 -0
  104. package/dist/util/rpc.js +69 -0
  105. package/dist/util/safeLog.d.ts +0 -1
  106. package/dist/util/safeLog.js +52 -53
  107. package/dist/util/scheduler.d.ts +0 -1
  108. package/dist/util/scheduler.js +53 -58
  109. package/dist/util/webhooks.d.ts +0 -1
  110. package/dist/util/webhooks.js +54 -58
  111. package/dist/wallet/ActionFeed.d.ts +3 -3
  112. package/dist/wallet/ActionFeed.js +189 -187
  113. package/dist/wallet/AgentWallet.d.ts +9 -7
  114. package/dist/wallet/AgentWallet.js +121 -141
  115. package/dist/wallet/ProfitTracker.d.ts +0 -1
  116. package/dist/wallet/ProfitTracker.js +71 -74
  117. package/package.json +12 -7
  118. package/scripts/build-esbuild.mjs +40 -0
  119. package/scripts/bundle-dts.mjs +58 -0
  120. package/scripts/minify.mjs +44 -0
  121. package/scripts/postinstall.js +27 -0
@@ -1,28 +1,25 @@
1
- /**
2
- * Global error handling utilities for AIAIAI agent
3
- */
1
+
4
2
  import { safeLog } from "./safeLog.js";
5
- // Generic error handler to wrap async operations
3
+
6
4
  export function withErrorHandling(operation, context) {
7
- return operation().catch((error) => {
8
- const errorMessage = error instanceof Error ? error.message : String(error);
9
- safeLog(`[${context}] ERROR: ${errorMessage}`);
10
- if (error instanceof Error) {
11
- safeLog(`Stack trace: ${error.stack}`);
12
- }
13
- throw error; // Re-throw to maintain expected behavior
14
- });
5
+ return operation().catch((error) => {
6
+ const errorMessage = error instanceof Error ? error.message : String(error);
7
+ safeLog(`[${context}] ERROR: ${errorMessage}`);
8
+ if (error instanceof Error) {
9
+ safeLog(`Stack trace: ${error.stack}`);
15
10
  }
16
- // Enhanced logging for unhandled promise rejections
11
+ throw error;
12
+ });
13
+ }
14
+
17
15
  export function setupGlobalErrorHandlers() {
18
- process.on('unhandledRejection', (reason, promise) => {
19
- console.error('[UNHANDLED_REJECTION] Reason:', reason);
20
- console.error('[PROMISE]', promise);
21
- process.exit(1);
22
- });
23
- process.on('uncaughtException', (error) => {
24
- console.error('[UNCAUGHT_EXCEPTION]', error);
25
- process.exit(1);
26
- });
16
+ process.on('unhandledRejection', (reason, promise) => {
17
+ console.error('[UNHANDLED_REJECTION] Reason:', reason);
18
+ console.error('[PROMISE]', promise);
19
+ process.exit(1);
20
+ });
21
+ process.on('uncaughtException', (error) => {
22
+ console.error('[UNCAUGHT_EXCEPTION]', error);
23
+ process.exit(1);
24
+ });
27
25
  }
28
- //# sourceMappingURL=errorHandler.js.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * #61: Structured error types with codes for consistent error handling
3
+ * #65: Error code system — AUTH_401, RATE_429, TIMEOUT_408, etc.
4
+ */
5
+ export type ErrorCode = 'AUTH_401' | 'RATE_429' | 'TIMEOUT_408' | 'PARSE_001' | 'RPC_ERROR' | 'NETWORK_ERROR' | 'VALIDATION_ERROR' | 'TOOL_ERROR' | 'UNKNOWN';
6
+ export declare class AgentError extends Error {
7
+ readonly code: ErrorCode;
8
+ readonly context?: Record<string, unknown>;
9
+ readonly timestamp: number;
10
+ readonly recoverable: boolean;
11
+ constructor(message: string, code?: ErrorCode, options?: {
12
+ context?: Record<string, unknown>;
13
+ recoverable?: boolean;
14
+ });
15
+ }
16
+ export declare class RpcError extends AgentError {
17
+ readonly method: string;
18
+ readonly statusCode?: number;
19
+ constructor(message: string, method: string, options?: {
20
+ statusCode?: number;
21
+ code?: ErrorCode;
22
+ context?: Record<string, unknown>;
23
+ });
24
+ }
25
+ export declare class ApiError extends AgentError {
26
+ readonly host: string;
27
+ readonly statusCode?: number;
28
+ constructor(message: string, host: string, options?: {
29
+ statusCode?: number;
30
+ code?: ErrorCode;
31
+ recoverable?: boolean;
32
+ });
33
+ }
34
+ export declare class ValidationError extends AgentError {
35
+ readonly field: string;
36
+ constructor(message: string, field: string, context?: Record<string, unknown>);
37
+ }
38
+ /**
39
+ * #62: Error aggregation — collect errors per session for /errors command
40
+ */
41
+ declare class ErrorAggregator {
42
+ private errors;
43
+ private maxErrors;
44
+ record(error: AgentError): void;
45
+ getRecent(count?: number): Array<{
46
+ error: AgentError;
47
+ ts: number;
48
+ }>;
49
+ getByCode(code: ErrorCode): AgentError[];
50
+ getSummary(): Record<string, number>;
51
+ clear(): void;
52
+ get count(): number;
53
+ }
54
+ export declare const errorAggregator: ErrorAggregator;
55
+ /**
56
+ * #66: User-friendly error messages with suggested actions
57
+ */
58
+ export declare function formatUserError(error: AgentError): string;
59
+ export {};
@@ -0,0 +1,93 @@
1
+
2
+ export class AgentError extends Error {
3
+ code;
4
+ context;
5
+ timestamp;
6
+ recoverable;
7
+ constructor(message, code = 'UNKNOWN', options) {
8
+ super(message);
9
+ this.name = 'AgentError';
10
+ this.code = code;
11
+ this.context = options?.context;
12
+ this.timestamp = Date.now();
13
+ this.recoverable = options?.recoverable ?? false;
14
+ }
15
+ }
16
+ export class RpcError extends AgentError {
17
+ method;
18
+ statusCode;
19
+ constructor(message, method, options) {
20
+ super(message, options?.code ?? 'RPC_ERROR', options);
21
+ this.name = 'RpcError';
22
+ this.method = method;
23
+ this.statusCode = options?.statusCode;
24
+ }
25
+ }
26
+ export class ApiError extends AgentError {
27
+ host;
28
+ statusCode;
29
+ constructor(message, host, options) {
30
+ super(message, options?.code ?? 'NETWORK_ERROR', options);
31
+ this.name = 'ApiError';
32
+ this.host = host;
33
+ this.statusCode = options?.statusCode;
34
+ }
35
+ }
36
+ export class ValidationError extends AgentError {
37
+ field;
38
+ constructor(message, field, context) {
39
+ super(message, 'VALIDATION_ERROR', { context, recoverable: true });
40
+ this.name = 'ValidationError';
41
+ this.field = field;
42
+ }
43
+ }
44
+
45
+ class ErrorAggregator {
46
+ errors = [];
47
+ maxErrors = 100;
48
+ record(error) {
49
+ this.errors.push({ error, ts: Date.now() });
50
+ if (this.errors.length > this.maxErrors) {
51
+ this.errors = this.errors.slice(-this.maxErrors);
52
+ }
53
+ }
54
+ getRecent(count = 20) {
55
+ return this.errors.slice(-count);
56
+ }
57
+ getByCode(code) {
58
+ return this.errors.filter(e => e.error.code === code).map(e => e.error);
59
+ }
60
+ getSummary() {
61
+ const summary = {};
62
+ for (const { error } of this.errors) {
63
+ summary[error.code] = (summary[error.code] ?? 0) + 1;
64
+ }
65
+ return summary;
66
+ }
67
+ clear() {
68
+ this.errors = [];
69
+ }
70
+ get count() {
71
+ return this.errors.length;
72
+ }
73
+ }
74
+ export const errorAggregator = new ErrorAggregator();
75
+
76
+ export function formatUserError(error) {
77
+ switch (error.code) {
78
+ case 'AUTH_401':
79
+ return `Authentication failed. Run: aiaiai setup`;
80
+ case 'RATE_429':
81
+ return `Rate limited. Wait a moment and try again.`;
82
+ case 'TIMEOUT_408':
83
+ return `Request timed out. Check your connection or try again.`;
84
+ case 'RPC_ERROR':
85
+ return `Solana RPC error. The network may be congested. Try again in 30s.`;
86
+ case 'NETWORK_ERROR':
87
+ return `Network error. Check your internet connection.`;
88
+ case 'VALIDATION_ERROR':
89
+ return `Invalid input: ${error.message}`;
90
+ default:
91
+ return error.message;
92
+ }
93
+ }
@@ -8,4 +8,3 @@ export declare const logger: {
8
8
  warn(context: string, message: string, meta?: unknown): void;
9
9
  error(context: string, message: string, meta?: unknown): void;
10
10
  };
11
- //# sourceMappingURL=logger.d.ts.map
@@ -1,43 +1,40 @@
1
- /**
2
- * src/util/logger.ts — Structured logging with levels for AIAIAI Agent
3
- */
1
+
4
2
  const LEVEL_PRIORITY = {
5
- debug: 0,
6
- info: 1,
7
- warn: 2,
8
- error: 3,
3
+ debug: 0,
4
+ info: 1,
5
+ warn: 2,
6
+ error: 3,
9
7
  };
10
8
  function getMinLevel() {
11
- const env = process.env.AIAIAI_LOG_LEVEL?.toLowerCase();
12
- if (env && env in LEVEL_PRIORITY)
13
- return env;
14
- return 'info';
9
+ const env = process.env.AIAIAI_LOG_LEVEL?.toLowerCase();
10
+ if (env && env in LEVEL_PRIORITY)
11
+ return env;
12
+ return 'info';
15
13
  }
16
14
  function shouldLog(level) {
17
- return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[getMinLevel()];
15
+ return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[getMinLevel()];
18
16
  }
19
17
  function formatMessage(level, context, message, meta) {
20
- const ts = new Date().toISOString();
21
- const prefix = `[${ts}] [${level.toUpperCase()}] [${context}]`;
22
- const metaStr = meta ? ` ${JSON.stringify(meta)}` : '';
23
- return `${prefix} ${message}${metaStr}`;
18
+ const ts = new Date().toISOString();
19
+ const prefix = `[${ts}] [${level.toUpperCase()}] [${context}]`;
20
+ const metaStr = meta ? ` ${JSON.stringify(meta)}` : '';
21
+ return `${prefix} ${message}${metaStr}`;
24
22
  }
25
23
  export const logger = {
26
- debug(context, message, meta) {
27
- if (shouldLog('debug'))
28
- console.error(formatMessage('debug', context, message, meta));
29
- },
30
- info(context, message, meta) {
31
- if (shouldLog('info'))
32
- console.error(formatMessage('info', context, message, meta));
33
- },
34
- warn(context, message, meta) {
35
- if (shouldLog('warn'))
36
- console.error(formatMessage('warn', context, message, meta));
37
- },
38
- error(context, message, meta) {
39
- if (shouldLog('error'))
40
- console.error(formatMessage('error', context, message, meta));
41
- },
24
+ debug(context, message, meta) {
25
+ if (shouldLog('debug'))
26
+ console.error(formatMessage('debug', context, message, meta));
27
+ },
28
+ info(context, message, meta) {
29
+ if (shouldLog('info'))
30
+ console.error(formatMessage('info', context, message, meta));
31
+ },
32
+ warn(context, message, meta) {
33
+ if (shouldLog('warn'))
34
+ console.error(formatMessage('warn', context, message, meta));
35
+ },
36
+ error(context, message, meta) {
37
+ if (shouldLog('error'))
38
+ console.error(formatMessage('error', context, message, meta));
39
+ },
42
40
  };
43
- //# sourceMappingURL=logger.js.map
@@ -2,4 +2,3 @@ export declare class ProcessManager {
2
2
  static setupGlobalHandlers(): void;
3
3
  static shutdown(exitCode: number): void;
4
4
  }
5
- //# sourceMappingURL=processManager.d.ts.map
@@ -1,39 +1,36 @@
1
- /**
2
- * Process management utilities for AIAIAI Agent
3
- */
1
+
4
2
  import { safeLog } from "./safeLog.js";
5
3
  export class ProcessManager {
6
- static setupGlobalHandlers() {
7
- // Handle uncaught exceptions
8
- process.on('uncaughtException', (error) => {
9
- safeLog('[UNCAUGHT_EXCEPTION] ' + error.message);
10
- if (error.stack) {
11
- safeLog('[STACK_TRACE] ' + error.stack);
12
- }
13
- // Gracefully shutdown
14
- this.shutdown(1);
15
- });
16
- // Handle unhandled promises
17
- process.on('unhandledRejection', (reason, promise) => {
18
- safeLog('[UNHANDLED_REJECTION] ' + reason?.message || String(reason));
19
- // Attempt graceful shutdown
20
- this.shutdown(1);
21
- });
22
- // Handle graceful shutdown signals
23
- process.on('SIGTERM', () => {
24
- safeLog('[SIGTERM] Received shutdown signal');
25
- this.shutdown(0);
26
- });
27
- process.on('SIGINT', () => {
28
- safeLog('[SIGINT] Received shutdown signal');
29
- this.shutdown(0);
30
- });
31
- }
32
- static shutdown(exitCode) {
33
- // Allow cleanup time
34
- setTimeout(() => {
35
- process.exit(exitCode);
36
- }, 100);
37
- }
4
+ static setupGlobalHandlers() {
5
+
6
+ process.on('uncaughtException', (error) => {
7
+ safeLog('[UNCAUGHT_EXCEPTION] ' + error.message);
8
+ if (error.stack) {
9
+ safeLog('[STACK_TRACE] ' + error.stack);
10
+ }
11
+
12
+ this.shutdown(1);
13
+ });
14
+
15
+ process.on('unhandledRejection', (reason, promise) => {
16
+ safeLog('[UNHANDLED_REJECTION] ' + reason?.message || String(reason));
17
+
18
+ this.shutdown(1);
19
+ });
20
+
21
+ process.on('SIGTERM', () => {
22
+ safeLog('[SIGTERM] Received shutdown signal');
23
+ this.shutdown(0);
24
+ });
25
+ process.on('SIGINT', () => {
26
+ safeLog('[SIGINT] Received shutdown signal');
27
+ this.shutdown(0);
28
+ });
29
+ }
30
+ static shutdown(exitCode) {
31
+
32
+ setTimeout(() => {
33
+ process.exit(exitCode);
34
+ }, 100);
35
+ }
38
36
  }
39
- //# sourceMappingURL=processManager.js.map
@@ -17,5 +17,10 @@ export interface CircuitState {
17
17
  state: "closed" | "open" | "half-open";
18
18
  }
19
19
  export declare function resilientFetch(url: string, options?: FetchOptions): Promise<Response>;
20
+ export declare function getCircuitStats(): Array<{
21
+ key: string;
22
+ state: string;
23
+ failures: number;
24
+ lastFailureTime: number;
25
+ }>;
20
26
  export declare function isReachable(url: string, timeout?: number): Promise<boolean>;
21
- //# sourceMappingURL=resilientFetch.d.ts.map
@@ -1,94 +1,148 @@
1
- /**
2
- * src/util/resilientFetch.ts - Resilient HTTP client with timeout, retry, circuit breaker
3
- */
1
+
2
+ import dns from 'node:dns';
3
+ import http from 'node:http';
4
+ import https from 'node:https';
5
+ import { AgentError, errorAggregator } from './errors.js';
6
+
7
+ let _requestIdCounter = 0;
8
+
9
+ const dnsCache = new Map();
10
+ const DNS_CACHE_TTL = 5 * 60_1000;
11
+ const dnsCacheTime = new Map();
4
12
  const circuits = new Map();
5
13
  const CIRCUIT_THRESHOLD = 3;
6
14
  const CIRCUIT_RESET_MS = 60_000;
15
+
16
+ const keepAliveAgent = new http.Agent({ keepAlive: true, maxSockets: 10, maxFreeSockets: 5 });
17
+ const httpsKeepAliveAgent = new https.Agent({ keepAlive: true, maxSockets: 10, maxFreeSockets: 5 });
7
18
  function getCircuit(key) {
8
- let c = circuits.get(key);
9
- if (!c) {
10
- c = { failures: 0, lastFailureTime: 0, state: "closed" };
11
- circuits.set(key, c);
12
- }
13
- return c;
19
+ let c = circuits.get(key);
20
+ if (!c) {
21
+ c = { failures: 0, lastFailureTime: 0, state: "closed" };
22
+ circuits.set(key, c);
23
+ }
24
+ return c;
14
25
  }
15
26
  function canExecute(key) {
16
- const c = getCircuit(key);
17
- if (c.state === "closed")
18
- return true;
19
- if (c.state === "open" && Date.now() - c.lastFailureTime > CIRCUIT_RESET_MS) {
20
- c.state = "half-open";
21
- return true;
22
- }
23
- return c.state === "half-open";
27
+ const c = getCircuit(key);
28
+ if (c.state === "closed")
29
+ return true;
30
+ if (c.state === "open" && Date.now() - c.lastFailureTime > CIRCUIT_RESET_MS) {
31
+ c.state = "half-open";
32
+ return true;
33
+ }
34
+ return c.state === "half-open";
24
35
  }
25
36
  function recordSuccess(key) {
26
- const c = getCircuit(key);
27
- c.failures = 0;
28
- c.state = "closed";
37
+ const c = getCircuit(key);
38
+ c.failures = 0;
39
+ c.state = "closed";
29
40
  }
30
41
  function recordFailure(key) {
31
- const c = getCircuit(key);
32
- c.failures++;
33
- c.lastFailureTime = Date.now();
34
- if (c.failures >= CIRCUIT_THRESHOLD) {
35
- c.state = "open";
36
- }
42
+ const c = getCircuit(key);
43
+ c.failures++;
44
+ c.lastFailureTime = Date.now();
45
+ if (c.failures >= CIRCUIT_THRESHOLD) {
46
+ c.state = "open";
47
+ }
37
48
  }
38
49
  export async function resilientFetch(url, options = {}) {
39
- const { timeout = 8_000, retries = 2, backoffMs = 1_000, onRetry, method = "GET", headers, body, signal: externalSignal, } = options;
40
- const circuitKey = new URL(url).hostname;
41
- if (!canExecute(circuitKey)) {
42
- throw new Error("Circuit open for " + circuitKey + " - service unavailable, retry later");
43
- }
44
- let lastError = null;
45
- for (let attempt = 0; attempt <= retries; attempt++) {
46
- const controller = new AbortController();
47
- const timer = setTimeout(() => controller.abort(), timeout);
48
- // Combine external abort signal with timeout
49
- if (externalSignal) {
50
- if (externalSignal.aborted)
51
- controller.abort();
52
- else
53
- externalSignal.addEventListener("abort", () => controller.abort(), { once: true });
54
- }
55
- try {
56
- const response = await fetch(url, {
57
- signal: controller.signal,
58
- method,
59
- headers,
60
- body,
61
- });
62
- clearTimeout(timer);
63
- if (!response.ok) {
64
- throw new Error("HTTP " + response.status + ": " + response.statusText);
65
- }
66
- recordSuccess(circuitKey);
67
- return response;
68
- }
69
- catch (error) {
70
- clearTimeout(timer);
71
- lastError = error instanceof Error ? error : new Error(String(error));
72
- if (attempt < retries) {
73
- onRetry?.(attempt + 1, lastError);
74
- const delay = backoffMs * Math.pow(2, attempt);
75
- await new Promise((r) => setTimeout(r, delay));
76
- }
77
- }
78
- }
79
- recordFailure(circuitKey);
80
- throw lastError;
50
+ const { timeout = 8_000, retries = 2, backoffMs = 1_000, onRetry, method = "GET", headers, body, signal: externalSignal, } = options;
51
+ const circuitKey = new URL(url).hostname;
52
+ if (!canExecute(circuitKey)) {
53
+ throw new Error("Circuit open for " + circuitKey + " - service unavailable, retry later");
54
+ }
55
+ let lastError = null;
56
+ for (let attempt = 0; attempt <= retries; attempt++) {
57
+ const controller = new AbortController();
58
+ const timer = setTimeout(() => controller.abort(), timeout);
59
+
60
+ if (externalSignal) {
61
+ if (externalSignal.aborted)
62
+ controller.abort();
63
+ else
64
+ externalSignal.addEventListener("abort", () => controller.abort(), { once: true });
65
+ }
66
+ try {
67
+
68
+ const urlObj = new URL(url);
69
+ const hostname = urlObj.hostname;
70
+ const now = Date.now();
71
+ const cachedIp = dnsCache.get(hostname);
72
+ const cachedTime = dnsCacheTime.get(hostname);
73
+ if (!cachedIp || !cachedTime || now - cachedTime > DNS_CACHE_TTL) {
74
+ try {
75
+ dns.resolve4(hostname, (err, ips) => {
76
+ if (!err && ips && ips.length > 0) {
77
+ dnsCache.set(hostname, ips[0]);
78
+ dnsCacheTime.set(hostname, now);
79
+ }
80
+ });
81
+ }
82
+ catch { }
83
+ }
84
+
85
+ const agent = urlObj.protocol === 'https:' ? httpsKeepAliveAgent : keepAliveAgent;
86
+
87
+ const fetchHeaders = { ...headers, 'Accept-Encoding': 'gzip' };
88
+ const fetchOpts = {
89
+ signal: controller.signal,
90
+ method,
91
+ headers: fetchHeaders,
92
+ body,
93
+ };
94
+
95
+ if (urlObj.protocol === 'https:' || urlObj.protocol === 'http:') {
96
+ fetchOpts.agent = urlObj.protocol === 'https:' ? httpsKeepAliveAgent : keepAliveAgent;
97
+ }
98
+ const response = await fetch(url, fetchOpts);
99
+ clearTimeout(timer);
100
+ if (!response.ok) {
101
+ throw new Error("HTTP " + response.status + ": " + response.statusText);
102
+ }
103
+ recordSuccess(circuitKey);
104
+ return response;
105
+ }
106
+ catch (error) {
107
+ clearTimeout(timer);
108
+ lastError = error instanceof Error ? error : new Error(String(error));
109
+ if (attempt < retries) {
110
+ onRetry?.(attempt + 1, lastError);
111
+
112
+ const baseDelay = backoffMs * Math.pow(2, attempt);
113
+ const jitter = baseDelay * 0.2 * (Math.random() * 2 - 1);
114
+ await new Promise((r) => setTimeout(r, baseDelay + jitter));
115
+ }
116
+ }
117
+ }
118
+ recordFailure(circuitKey);
119
+
120
+ if (lastError) {
121
+ const aggError = new AgentError(lastError.message, 'NETWORK_ERROR', {
122
+ context: { url, attempts: retries + 1 },
123
+ recoverable: true,
124
+ });
125
+ errorAggregator.record(aggError);
126
+ }
127
+ throw lastError;
128
+ }
129
+
130
+ export function getCircuitStats() {
131
+ const stats = [];
132
+ for (const [key, c] of circuits) {
133
+ stats.push({ key, state: c.state, failures: c.failures, lastFailureTime: c.lastFailureTime });
134
+ }
135
+ return stats;
81
136
  }
82
137
  export async function isReachable(url, timeout = 5_000) {
83
- try {
84
- const controller = new AbortController();
85
- const timer = setTimeout(() => controller.abort(), timeout);
86
- const res = await fetch(url, { signal: controller.signal });
87
- clearTimeout(timer);
88
- return res.ok;
89
- }
90
- catch {
91
- return false;
92
- }
93
- }
94
- //# sourceMappingURL=resilientFetch.js.map
138
+ try {
139
+ const controller = new AbortController();
140
+ const timer = setTimeout(() => controller.abort(), timeout);
141
+ const res = await fetch(url, { signal: controller.signal });
142
+ clearTimeout(timer);
143
+ return res.ok;
144
+ }
145
+ catch {
146
+ return false;
147
+ }
148
+ }
@@ -24,4 +24,3 @@ export declare function cacheStats(): {
24
24
  size: number;
25
25
  entries: string[];
26
26
  };
27
- //# sourceMappingURL=responseCache.d.ts.map