Browse Source

docs: update constitution to v1.5.0 and establish development guidelines

Constitution Updates:
- Enhance Principle I: Add TypeScript code quality standards
- Enhance Principle V: Add credential management security requirements
- Add code quality assurance in operational constraints
- Strengthen testing and code review standards
- Update governance with compliance checking requirements

Development Guidelines:
- Establish import statement standards (no file extensions)
- Configure ESLint rules for import validation
- Set up Prettier auto-formatting
- Document IDE configuration for team consistency

Technical Improvements:
- Apply ESLint auto-fixes across codebase
- Standardize import statement formatting
- Update package dependencies for linting

This establishes enterprise-grade development standards while
maintaining backward compatibility with existing trading principles.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
helium3@sina.com 1 week ago
parent
commit
76b0987bb1

+ 53 - 3
.eslintrc.json

@@ -10,10 +10,12 @@
     "sourceType": "module",
     "ecmaVersion": 2020
   },
-  "plugins": ["@typescript-eslint", "prettier"],
+  "plugins": ["@typescript-eslint", "prettier", "import"],
   "extends": [
     "prettier",
-    "plugin:@typescript-eslint/recommended"
+    "plugin:@typescript-eslint/recommended",
+    "plugin:import/recommended",
+    "plugin:import/typescript"
     // Uncomment the following lines to enable the recommended rules for type checking.
     //    "plugin:@typescript-eslint/recommended-requiring-type-checking",
   ],
@@ -35,6 +37,54 @@
     "@typescript-eslint/no-var-requires": 0,
     "@typescript-eslint/no-explicit-any": 0,
     // disable error for unused vars
-    "no-unused-vars": 0
+    "no-unused-vars": 0,
+    // Import 规则:禁止在 import 语句中使用文件扩展名
+    "import/extensions": [
+      "error",
+      "ignorePackages",
+      {
+        "js": "never",
+        "jsx": "never",
+        "ts": "never",
+        "tsx": "never"
+      }
+    ],
+    // 确保 import 路径存在且正确
+    "import/no-unresolved": "error",
+    // 禁止重复导入
+    "import/no-duplicates": "error",
+    // import 语句排序
+    "import/order": [
+      "error",
+      {
+        "groups": [
+          "builtin",
+          "external",
+          "internal",
+          "parent",
+          "sibling",
+          "index"
+        ],
+        "newlines-between": "always",
+        "alphabetize": {
+          "order": "asc",
+          "caseInsensitive": true
+        }
+      }
+    ]
+  },
+  "settings": {
+    "import/resolver": {
+      "typescript": {
+        "alwaysTryTypes": true,
+        "project": "./tsconfig.json"
+      },
+      "node": {
+        "extensions": [".js", ".jsx", ".ts", ".tsx"]
+      }
+    },
+    "import/parsers": {
+      "@typescript-eslint/parser": [".ts", ".tsx"]
+    }
   }
 }

+ 35 - 8
.specify/memory/constitution.md

@@ -1,12 +1,15 @@
 # 多交易所Delta中性宪章
 <!--
 同步影响报告
-版本: 1.3.0 → 1.4.0
-修改原则: 更新原则一从"库优先"改为"集成优先",强调实际业务集成而非抽象复用,反映通用HTTP客户端库的实用性导向和现代化架构实践
-添加章节: 增强了运营约束以包含HTTP客户端库性能要求
+版本: 1.4.0 → 1.5.0
+修改原则:
+- 增强原则一:添加TypeScript类型安全和代码质量标准
+- 增强原则五:加强安全实践和凭证管理要求
+- 新增代码质量约束:ESLint配置、import规范、TDD实践
+添加章节: 代码质量和安全实践强化
 删除章节: 无
 需要更新的模板:
-- ✅ .specify/templates/plan-template.md (已更新宪章版本引用 1.3.0 → 1.4.0)
+- ✅ .specify/templates/plan-template.md (已更新宪章版本引用 1.4.0 → 1.5.0)
 - ✅ .specify/templates/spec-template.md (无需更改)
 - ✅ .specify/templates/tasks-template.md (无需更改)
 - ✅ .specify/templates/commands/*.md (无需更改)
@@ -15,11 +18,18 @@
 
 ## 核心原则
 
-### 一、集成优先架构与现实测试
-追求高内聚低耦合的设计思维,编写结构良好、可集成的代码。为实际业务集成而设计,而非为了抽象而变复杂,避免过度设计。系统必须支持模块化、组件化、服务化架构,优先考虑与现有系统的无缝集成,便于敏捷开发、持续集成和高扩展性。
+### 一、优先架构与现实测试
+追求高内聚低耦合的设计思维,编写结构良好、可集成、模块化程度高的代码。为实际业务集成而设计,而非为了抽象而变复杂,避免过度设计。系统必须支持模块化、组件化、服务化架构,优先考虑与现有系统的无缝集成,便于敏捷开发、持续集成和高扩展性。
 
 核心HTTP客户端库必须维持企业级性能标准:响应时间<100ms、99.9%可用性、支持1000+并发请求。所有平台适配器必须实现统一接口,支持Ed25519(Pacifica)、EIP-191(Aster)、HMAC-SHA256(Binance)认证。代理管理必须包含负载均衡、健康检查、自动故障转移。
 
+**TypeScript代码质量标准:**
+- 必须使用严格的TypeScript配置,禁用any类型
+- import语句必须不含文件扩展名,使用路径别名(@/)
+- ESLint规则必须强制执行:import/extensions、import/order、import/no-unresolved
+- 所有模块必须提供完整的类型定义和导出接口
+- 代码格式化必须通过Prettier自动执行,保存时自动修复
+
 测试必须使用现实环境:
 - 优先使用真实数据库而非模拟
 - 使用实际服务实例而非存根
@@ -28,6 +38,7 @@
 - 性能测试必须在生产类似环境中进行
 - 所有测试必须在CI中自动运行
 - HTTP客户端库必须通过TDD开发,测试先行
+- 契约测试必须先于实现,确保测试失败后再开发功能
 
 ### 二、Delta中性优先
 所有策略必须在任何时候都针对所有连接的交易所和账户对保持总Delta ≈ 0。除非缓解订单已在途中并已记录,否则每个资产的净敞口必须保持在±0.0005 BTC等值内。当利用率或敞口突破配置阈值时,必须立即进行重新平衡。
@@ -38,9 +49,17 @@
 ### 四、资金保护与风险控制
 每个账户必须执行可配置的头寸、杠杆和回撤上限。紧急止损路径必须在触发后30秒内取消或对冲剩余敞口。所有订单流必须携带幂等标识符和回滚计划,以防止部分失败期间的孤立敞口。HTTP客户端必须实现全面错误处理、自动重试机制和熔断器模式。
 
-### 五、透明可观测性与审计
+### 五、透明可观测性与安全审计
 执行、对冲和清理服务必须为每个账户和交易所发出结构化日志、指标和健康信号。订单意图、成交、取消和余额快照必须通过关联ID进行端到端可追踪。历史操作必须通过持久化配置和可重放事件日志保持可重现性。HTTP客户端必须提供性能监控、SLA跟踪和实时健康检查。
 
+**凭证管理安全要求:**
+- 凭证管理模块必须支持多平台热加载,配置更新在100ms内完成
+- 所有私钥和API密钥必须在静态时加密存储,传输时使用安全通道
+- 签名操作必须在50ms内完成,支持Ed25519、EIP-191、HMAC-SHA256算法
+- 平台检测必须智能识别账户类型,自动选择对应签名方法
+- 凭证轮换程序必须每季度演练,支持零停机时间更新
+- 审计日志必须记录所有凭证访问、签名操作和配置变更
+
 ## 运营约束
 平台必须维持高频信号评估(≤8秒循环),同时保持每次迭代计算在配置预算内。网络访问必须在需要时通过批准的代理路由,而不破坏延迟承诺。HTTP客户端代理池必须支持地理合规、IP轮换和自动故障转移。
 
@@ -48,6 +67,9 @@
 
 API响应缓存必须考虑数据新鲜度要求,批量请求处理必须包含并发控制和错误隔离。连接池管理必须优化资源利用率并防止连接泄漏。
 
+**代码质量保障:**
+开发环境必须配置自动化代码质量检查,包括ESLint规则验证、TypeScript类型检查和Prettier格式化。所有Pull Request必须通过代码质量门槛,包含完整类型声明、规范的import语句和通过的测试覆盖率。工程师IDE必须配置统一的开发规范,确保代码一致性。
+
 ## 工作流程与质量门槛
 规划产物必须在开发开始前明确将功能映射到这些原则。规格必须声明敞口限制、数据源和测试矩阵。计划和任务必须安排对冲、订单清理、可观测性改进以及HTTP客户端库性能验证的TDD覆盖。
 
@@ -55,9 +77,14 @@ API响应缓存必须考虑数据新鲜度要求,批量请求处理必须包
 
 新的平台集成必须完整实现数据接口(价格、订单簿、K线、交易历史)和操作接口(订单创建、修改、取消、批量操作),包括WebSocket实时数据流和全面的错误处理。
 
+**代码审查标准:**
+代码审查必须验证TypeScript类型安全、import语句规范性、ESLint合规性和测试覆盖率。凭证管理相关代码必须经过安全审查,确保敏感信息处理符合最佳实践。所有模块化组件必须提供清晰的导出接口和使用文档。
+
 ## 治理
 本宪章取代交易堆栈的先前流程指导。修正案需要维护者共识、对保障措施影响的文档以及对依赖模板的更新。版本控制遵循SemVer:主要版本用于原则删除/不兼容治理,次要版本用于新原则或重大范围增加,补丁版本用于澄清。
 
 合规性审查必须至少每月进行一次,检查敞口报告、健康警报、测试覆盖率变化以及HTTP客户端库性能指标。偏差必须记录修复负责人和时间线。库的发布必须遵循语义版本控制,包含完整的变更日志和迁移指南。
 
-**版本**: 1.4.0 | **批准**: 2025-09-27 | **最后修订**: 2025-09-28
+代码质量合规性检查必须包括ESLint规则遵守率、TypeScript编译错误率、import语句规范性和测试覆盖率指标。凭证管理模块的安全审查必须验证加密存储、访问控制和审计日志完整性。
+
+**版本**: 1.5.0 | **批准**: 2025-09-27 | **最后修订**: 2025-09-29

+ 1 - 1
.specify/templates/plan-template.md

@@ -203,4 +203,4 @@ ios/ 或 android/
 - [ ] 复杂度偏差已记录
 
 ---
-*基于宪章 v1.4.0 - 详见 `/memory/constitution.md`*
+*基于宪章 v1.5.0 - 详见 `/memory/constitution.md`*

+ 144 - 0
DEVELOPMENT.md

@@ -0,0 +1,144 @@
+# 开发规范 (Development Guidelines)
+
+## Import 语句规范
+
+### ❌ 禁止使用文件扩展名
+
+**错误示例:**
+```typescript
+// ❌ 不要这样写
+import { CredentialManager } from './credential-manager/CredentialManager.js'
+import { Platform } from '../types/credential.ts'
+import utils from './utils/helper.js'
+```
+
+**正确示例:**
+```typescript
+// ✅ 正确写法
+import { CredentialManager } from './credential-manager/CredentialManager'
+import { Platform } from '../types/credential'
+import utils from './utils/helper'
+```
+
+### 📁 推荐的 Import 模式
+
+#### 1. 使用路径别名(Path Aliases)
+```typescript
+// ✅ 推荐:使用配置的路径别名
+import { CredentialManager } from '@/core/credential-manager'
+import { Platform } from '@/types/credential'
+import { logger } from '@/utils/logger'
+```
+
+#### 2. Import 顺序规范
+```typescript
+// 1. Node.js 内置模块
+import { readFile } from 'fs'
+import { join } from 'path'
+
+// 2. 第三方 npm 包
+import { describe, test, expect } from '@jest/globals'
+import axios from 'axios'
+
+// 3. 内部模块(@/ 开头)
+import { CredentialManager } from '@/core/credential-manager'
+import { Platform } from '@/types/credential'
+
+// 4. 相对路径导入
+import { helper } from '../utils/helper'
+import { config } from './config'
+```
+
+## ESLint 自动检查
+
+项目已配置 ESLint 规则自动检查 import 语句:
+
+### 启用的规则:
+- `import/extensions`: 禁止使用文件扩展名
+- `import/no-unresolved`: 确保导入路径存在
+- `import/no-duplicates`: 禁止重复导入
+- `import/order`: 自动排序导入语句
+
+### 运行检查:
+```bash
+# 检查所有文件
+npm run lint
+
+# 自动修复可修复的问题
+npm run lint:fix
+
+# 检查特定文件
+npx eslint src/path/to/file.ts
+```
+
+## IDE 配置建议
+
+### VS Code 配置
+
+在 `.vscode/settings.json` 中添加:
+```json
+{
+  "typescript.suggest.includeCompletionsForModuleExports": true,
+  "typescript.suggest.includeCompletionsWithInsertText": true,
+  "typescript.preferences.includePackageJsonAutoImports": "auto",
+  "typescript.suggest.autoImports": true,
+
+  // 自动移除文件扩展名
+  "typescript.suggest.paths": false,
+
+  // ESLint 自动修复
+  "editor.codeActionsOnSave": {
+    "source.fixAll.eslint": true,
+    "source.organizeImports": true
+  },
+
+  // 保存时自动格式化
+  "editor.formatOnSave": true
+}
+```
+
+### WebStorm/IntelliJ 配置
+
+1. 进入 **Settings > Editor > Code Style > TypeScript > Imports**
+2. 设置 **Use relative imports for files in the same directory**: `false`
+3. 设置 **Import with file extension**: `Never`
+4. 启用 **ESLint** 集成:**Settings > Languages > JavaScript > Code Quality Tools > ESLint**
+
+## 常见问题解决
+
+### Q: 为什么要禁止文件扩展名?
+A:
+1. **兼容性**:TypeScript 编译后的输出可能改变文件扩展名
+2. **一致性**:保持代码风格统一
+3. **重构友好**:文件重命名时不需要更新所有引用
+4. **构建优化**:打包工具能更好地处理模块解析
+
+### Q: ESLint 报错 "Unable to resolve path to module"
+A:
+1. 确保 `tsconfig.json` 中的 `paths` 配置正确
+2. 检查文件是否存在
+3. 运行 `npm install` 确保依赖安装完整
+
+### Q: 自动导入还是带扩展名怎么办?
+A:
+1. 更新 IDE 设置(参考上面的配置)
+2. 使用 `npm run lint:fix` 自动修复
+3. 手动移除扩展名
+
+## 团队协作
+
+### 代码审查清单
+- [ ] 所有 import 语句都没有文件扩展名
+- [ ] 使用了路径别名(@/)而不是深层相对路径
+- [ ] Import 语句按规范排序
+- [ ] ESLint 检查通过
+
+### Git Hook 建议
+```bash
+# 在 .husky/pre-commit 中添加
+npm run lint
+```
+
+---
+
+**记住**:一致的 import 风格让代码更易读、易维护!🚀

+ 3 - 3
__tests__/setup.ts

@@ -11,13 +11,13 @@ global.console = {
   info: jest.fn(),
   warn: console.warn,
   error: console.error,
-};
+}
 
 // Setup for credential manager tests
 beforeAll(() => {
   // Global setup if needed
-});
+})
 
 afterAll(() => {
   // Global cleanup if needed
-});
+})

File diff suppressed because it is too large
+ 957 - 46
package-lock.json


+ 2 - 0
package.json

@@ -18,6 +18,8 @@
     "@typescript-eslint/parser": "~6.2",
     "eslint": "~8.46",
     "eslint-config-prettier": "~9.0",
+    "eslint-import-resolver-typescript": "^4.4.4",
+    "eslint-plugin-import": "^2.32.0",
     "eslint-plugin-prettier": "^5.1.1",
     "glob": "^11.0.3",
     "jest": "^29.7.0",

+ 2 - 1
src/adapters/base/BaseAdapter.ts

@@ -6,6 +6,8 @@
  */
 
 import { EventEmitter } from 'events'
+
+import type { TimeoutConfig, RetryConfig } from '@/types/httpClient'
 import type {
   IPlatformAdapter,
   PlatformRequest,
@@ -18,7 +20,6 @@ import type {
   ProxyConfig,
   RawResponse,
 } from '@/types/platformAdapter'
-import type { TimeoutConfig, RetryConfig } from '@/types/httpClient'
 import { HttpClient } from '@/utils/httpClient'
 
 /**

+ 6 - 4
src/adapters/pacifica/PacificaClient.ts

@@ -4,16 +4,18 @@
  * 整合数据接口和交易操作接口,提供完整的Pacifica DEX API访问能力
  */
 
-import { UniversalHttpClient } from '@/utils/universalHttpClient'
-import { PacificaDataClient } from './PacificaDataClient'
-import { PacificaTradingClient } from './PacificaTradingClient'
+import WebSocket from 'ws'
+
 import {
   PacificaConfig,
   PacificaApiResponse,
   PacificaWebSocketMessage,
   PacificaWebSocketSubscription,
 } from '@/types/pacifica'
-import WebSocket from 'ws'
+import { UniversalHttpClient } from '@/utils/universalHttpClient'
+
+import { PacificaDataClient } from './PacificaDataClient'
+import { PacificaTradingClient } from './PacificaTradingClient'
 
 export class PacificaClient {
   private httpClient: UniversalHttpClient

+ 1 - 1
src/adapters/pacifica/PacificaDataClient.ts

@@ -5,7 +5,6 @@
  * 包括价格、订单簿、K线、交易历史等
  */
 
-import { UniversalHttpClient } from '@/utils/universalHttpClient'
 import { HttpClientRequest, HttpClientResponse } from '@/types/httpClient'
 import {
   PacificaPriceData,
@@ -19,6 +18,7 @@ import {
   PacificaApiResponse,
   PacificaListResponse,
 } from '@/types/pacifica'
+import { UniversalHttpClient } from '@/utils/universalHttpClient'
 
 export class PacificaDataClient {
   private httpClient: UniversalHttpClient

+ 1 - 1
src/adapters/pacifica/PacificaTradingClient.ts

@@ -5,7 +5,6 @@
  * 包括订单创建、限价单、市价单、取消订单、批量操作等
  */
 
-import { UniversalHttpClient } from '@/utils/universalHttpClient'
 import { HttpClientRequest, HttpClientResponse } from '@/types/httpClient'
 import {
   PacificaOrderRequest,
@@ -26,6 +25,7 @@ import {
   PacificaListResponse,
   PacificaFill,
 } from '@/types/pacifica'
+import { UniversalHttpClient } from '@/utils/universalHttpClient'
 
 export class PacificaTradingClient {
   private httpClient: UniversalHttpClient

+ 3 - 2
src/adapters/pacifica/index.ts

@@ -12,9 +12,10 @@ export { PacificaTradingClient } from './PacificaTradingClient'
 // 重新导出Pacifica类型
 export * from '@/types/pacifica'
 
-import { PacificaClient } from './PacificaClient'
-import { UniversalHttpClient } from '@/utils/universalHttpClient'
 import type { PacificaConfig } from '@/types/pacifica'
+import { UniversalHttpClient } from '@/utils/universalHttpClient'
+
+import { PacificaClient } from './PacificaClient'
 
 /**
  * 创建Pacifica客户端实例的便捷函数

+ 126 - 128
src/core/credential-manager/ConfigLoader.ts

@@ -5,8 +5,9 @@
  * Supports hot reloading and performance monitoring.
  */
 
-import * as fs from 'fs/promises';
-import * as path from 'path';
+import * as fs from 'fs/promises'
+import * as path from 'path'
+
 import {
   IConfigLoader,
   LoadResult,
@@ -15,24 +16,25 @@ import {
   AccountConfig,
   Platform,
   CredentialErrorCode,
-  CredentialManagerError
-} from '@/types/credential';
-import { CredentialValidator } from './CredentialValidator';
-import { PlatformDetector } from './PlatformDetector';
+  CredentialManagerError,
+} from '@/types/credential'
+
+import { CredentialValidator } from './CredentialValidator'
+import { PlatformDetector } from './PlatformDetector'
 
 /**
  * Configuration loader implementation
  */
 export class ConfigLoader implements IConfigLoader {
-  private validator = new CredentialValidator();
-  private platformDetector = new PlatformDetector();
-  private watchCallbacks = new Map<string, (accounts: Account[]) => void>();
+  private validator = new CredentialValidator()
+  private platformDetector = new PlatformDetector()
+  private watchCallbacks = new Map<string, (accounts: Account[]) => void>()
 
   /**
    * Load configuration file (JSON or YAML)
    */
   async loadConfig(filePath: string): Promise<LoadResult> {
-    const startTime = Date.now();
+    const startTime = Date.now()
 
     try {
       // Validate file path
@@ -41,49 +43,49 @@ export class ConfigLoader implements IConfigLoader {
           success: false,
           accounts: [],
           errors: ['Invalid file path provided'],
-          loadTime: Date.now() - startTime
-        };
+          loadTime: Date.now() - startTime,
+        }
       }
 
       // Check if file exists
       try {
-        await fs.access(filePath);
+        await fs.access(filePath)
       } catch (error) {
         return {
           success: false,
           accounts: [],
           errors: [`Configuration file not found: ${filePath}`],
           loadTime: Date.now() - startTime,
-          filePath
-        };
+          filePath,
+        }
       }
 
       // Read file contents
-      let fileContent: string;
+      let fileContent: string
       try {
-        fileContent = await fs.readFile(filePath, 'utf-8');
+        fileContent = await fs.readFile(filePath, 'utf-8')
       } catch (error) {
         return {
           success: false,
           accounts: [],
           errors: [`Failed to read configuration file: ${error instanceof Error ? error.message : 'Unknown error'}`],
           loadTime: Date.now() - startTime,
-          filePath
-        };
+          filePath,
+        }
       }
 
       // Parse configuration
-      let configData: ConfigFile;
+      let configData: ConfigFile
       try {
-        configData = this.parseConfigFile(fileContent, filePath);
+        configData = this.parseConfigFile(fileContent, filePath)
       } catch (error) {
         return {
           success: false,
           accounts: [],
           errors: [`Failed to parse configuration file: ${error instanceof Error ? error.message : 'Unknown error'}`],
           loadTime: Date.now() - startTime,
-          filePath
-        };
+          filePath,
+        }
       }
 
       // Validate configuration structure
@@ -94,33 +96,33 @@ export class ConfigLoader implements IConfigLoader {
           errors: ['Invalid configuration file structure'],
           loadTime: Date.now() - startTime,
           filePath,
-          version: configData.version
-        };
+          version: configData.version,
+        }
       }
 
       // Validate accounts
-      const validationResults = this.validator.validateAccountConfigs(configData.accounts);
-      const errors: string[] = [];
-      const validAccounts: Account[] = [];
+      const validationResults = this.validator.validateAccountConfigs(configData.accounts)
+      const errors: string[] = []
+      const validAccounts: Account[] = []
 
       for (let i = 0; i < configData.accounts.length; i++) {
-        const accountConfig = configData.accounts[i];
-        const validationResult = validationResults[i];
+        const accountConfig = configData.accounts[i]
+        const validationResult = validationResults[i]
 
         if (validationResult.isValid) {
           // Convert config to account
-          const account = this.convertConfigToAccount(accountConfig);
-          validAccounts.push(account);
+          const account = this.convertConfigToAccount(accountConfig)
+          validAccounts.push(account)
         } else {
-          errors.push(`Account ${accountConfig?.id || i}: ${validationResult.errors.join(', ')}`);
+          errors.push(`Account ${accountConfig?.id || i}: ${validationResult.errors.join(', ')}`)
         }
       }
 
-      const loadTime = Date.now() - startTime;
+      const loadTime = Date.now() - startTime
 
       // Performance check
       if (loadTime >= 100) {
-        errors.push(`Configuration load time (${loadTime}ms) exceeds performance requirement (<100ms)`);
+        errors.push(`Configuration load time (${loadTime}ms) exceeds performance requirement (<100ms)`)
       }
 
       return {
@@ -129,17 +131,16 @@ export class ConfigLoader implements IConfigLoader {
         errors: errors.length > 0 ? errors : undefined,
         loadTime,
         filePath,
-        version: configData.version
-      };
-
+        version: configData.version,
+      }
     } catch (error) {
       return {
         success: false,
         accounts: [],
         errors: [`Unexpected error loading configuration: ${error instanceof Error ? error.message : 'Unknown error'}`],
         loadTime: Date.now() - startTime,
-        filePath
-      };
+        filePath,
+      }
     }
   }
 
@@ -148,25 +149,19 @@ export class ConfigLoader implements IConfigLoader {
    */
   watchConfig(filePath: string, callback: (accounts: Account[]) => void): void {
     if (!filePath || typeof filePath !== 'string') {
-      throw new CredentialManagerError(
-        CredentialErrorCode.FILE_WATCH_FAILED,
-        'Invalid file path for watching'
-      );
+      throw new CredentialManagerError(CredentialErrorCode.FILE_WATCH_FAILED, 'Invalid file path for watching')
     }
 
     if (typeof callback !== 'function') {
-      throw new CredentialManagerError(
-        CredentialErrorCode.FILE_WATCH_FAILED,
-        'Callback must be a function'
-      );
+      throw new CredentialManagerError(CredentialErrorCode.FILE_WATCH_FAILED, 'Callback must be a function')
     }
 
     // Store callback for this file path
-    this.watchCallbacks.set(filePath, callback);
+    this.watchCallbacks.set(filePath, callback)
 
     // Note: In a real implementation, this would use fs.watch or chokidar
     // For now, we'll set up a simple polling mechanism for demonstration
-    this.setupFileWatching(filePath, callback);
+    this.setupFileWatching(filePath, callback)
   }
 
   /**
@@ -174,7 +169,7 @@ export class ConfigLoader implements IConfigLoader {
    */
   stopWatching(): void {
     // Clear all callbacks
-    this.watchCallbacks.clear();
+    this.watchCallbacks.clear()
 
     // Note: In a real implementation, this would close file watchers
     // For now, this is a placeholder
@@ -184,21 +179,25 @@ export class ConfigLoader implements IConfigLoader {
    * Parse configuration file (JSON or YAML)
    */
   private parseConfigFile(content: string, filePath: string): ConfigFile {
-    const extension = path.extname(filePath).toLowerCase();
+    const extension = path.extname(filePath).toLowerCase()
 
     if (extension === '.json') {
-      return this.parseJsonConfig(content);
+      return this.parseJsonConfig(content)
     } else if (extension === '.yaml' || extension === '.yml') {
-      return this.parseYamlConfig(content);
+      return this.parseYamlConfig(content)
     } else {
       // Try JSON first, then YAML
       try {
-        return this.parseJsonConfig(content);
+        return this.parseJsonConfig(content)
       } catch (jsonError) {
         try {
-          return this.parseYamlConfig(content);
+          return this.parseYamlConfig(content)
         } catch (yamlError) {
-          throw new Error(`Unsupported file format. Failed to parse as JSON: ${jsonError instanceof Error ? jsonError.message : 'Unknown error'}. Failed to parse as YAML: ${yamlError instanceof Error ? yamlError.message : 'Unknown error'}`);
+          throw new Error(
+            `Unsupported file format. Failed to parse as JSON: ${
+              jsonError instanceof Error ? jsonError.message : 'Unknown error'
+            }. Failed to parse as YAML: ${yamlError instanceof Error ? yamlError.message : 'Unknown error'}`,
+          )
         }
       }
     }
@@ -209,10 +208,10 @@ export class ConfigLoader implements IConfigLoader {
    */
   private parseJsonConfig(content: string): ConfigFile {
     try {
-      const parsed = JSON.parse(content);
-      return this.normalizeConfig(parsed);
+      const parsed = JSON.parse(content)
+      return this.normalizeConfig(parsed)
     } catch (error) {
-      throw new Error(`Invalid JSON format: ${error instanceof Error ? error.message : 'Unknown error'}`);
+      throw new Error(`Invalid JSON format: ${error instanceof Error ? error.message : 'Unknown error'}`)
     }
   }
 
@@ -224,11 +223,11 @@ export class ConfigLoader implements IConfigLoader {
     // In production, you would use a proper YAML library like 'js-yaml'
     try {
       // Convert basic YAML to JSON and parse
-      const jsonContent = this.basicYamlToJson(content);
-      const parsed = JSON.parse(jsonContent);
-      return this.normalizeConfig(parsed);
+      const jsonContent = this.basicYamlToJson(content)
+      const parsed = JSON.parse(jsonContent)
+      return this.normalizeConfig(parsed)
     } catch (error) {
-      throw new Error(`Invalid YAML format: ${error instanceof Error ? error.message : 'Unknown error'}`);
+      throw new Error(`Invalid YAML format: ${error instanceof Error ? error.message : 'Unknown error'}`)
     }
   }
 
@@ -238,68 +237,67 @@ export class ConfigLoader implements IConfigLoader {
   private basicYamlToJson(yaml: string): string {
     // This is a very basic implementation for demonstration
     // In production, use a proper YAML library
-    const lines = yaml.split('\n');
-    const result: any = {};
-    const stack: any[] = [result];
-    let currentIndent = 0;
+    const lines = yaml.split('\n')
+    const result: any = {}
+    const stack: any[] = [result]
+    let currentIndent = 0
 
     for (const line of lines) {
-      const trimmed = line.trim();
-      if (!trimmed || trimmed.startsWith('#')) continue;
+      const trimmed = line.trim()
+      if (!trimmed || trimmed.startsWith('#')) continue
 
-      const indent = line.length - line.trimLeft().length;
+      const indent = line.length - line.trimLeft().length
 
       if (trimmed.includes(':')) {
-        const [key, ...valueParts] = trimmed.split(':');
-        const value = valueParts.join(':').trim();
+        const [key, ...valueParts] = trimmed.split(':')
+        const value = valueParts.join(':').trim()
 
         if (value) {
           // Simple key-value pair
-          stack[stack.length - 1][key.trim()] = this.parseYamlValue(value);
+          stack[stack.length - 1][key.trim()] = this.parseYamlValue(value)
         } else {
           // Start of nested object
-          const newObj = {};
-          stack[stack.length - 1][key.trim()] = newObj;
+          const newObj = {}
+          stack[stack.length - 1][key.trim()] = newObj
           if (indent > currentIndent) {
-            stack.push(newObj);
-            currentIndent = indent;
+            stack.push(newObj)
+            currentIndent = indent
           }
         }
       } else if (trimmed.startsWith('-')) {
         // Array item
-        const value = trimmed.substring(1).trim();
-        const current = stack[stack.length - 1];
+        const value = trimmed.substring(1).trim()
+        const current = stack[stack.length - 1]
         if (!Array.isArray(current.accounts)) {
-          current.accounts = [];
+          current.accounts = []
         }
-        current.accounts.push(this.parseYamlValue(value));
+        current.accounts.push(this.parseYamlValue(value))
       }
     }
 
-    return JSON.stringify(result);
+    return JSON.stringify(result)
   }
 
   /**
    * Parse YAML value to appropriate type
    */
   private parseYamlValue(value: string): any {
-    const trimmed = value.trim();
+    const trimmed = value.trim()
 
-    if (trimmed === 'true') return true;
-    if (trimmed === 'false') return false;
-    if (trimmed === 'null') return null;
+    if (trimmed === 'true') return true
+    if (trimmed === 'false') return false
+    if (trimmed === 'null') return null
 
     // Try parsing as number
-    if (/^\d+$/.test(trimmed)) return parseInt(trimmed, 10);
-    if (/^\d+\.\d+$/.test(trimmed)) return parseFloat(trimmed);
+    if (/^\d+$/.test(trimmed)) return parseInt(trimmed, 10)
+    if (/^\d+\.\d+$/.test(trimmed)) return parseFloat(trimmed)
 
     // Remove quotes if present
-    if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
-        (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
-      return trimmed.slice(1, -1);
+    if ((trimmed.startsWith('"') && trimmed.endsWith('"')) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
+      return trimmed.slice(1, -1)
     }
 
-    return trimmed;
+    return trimmed
   }
 
   /**
@@ -307,14 +305,14 @@ export class ConfigLoader implements IConfigLoader {
    */
   private normalizeConfig(data: any): ConfigFile {
     if (!data || typeof data !== 'object') {
-      throw new Error('Configuration must be an object');
+      throw new Error('Configuration must be an object')
     }
 
     return {
       version: data.version || '1.0',
       accounts: Array.isArray(data.accounts) ? data.accounts : [],
-      metadata: data.metadata || {}
-    };
+      metadata: data.metadata || {},
+    }
   }
 
   /**
@@ -322,18 +320,18 @@ export class ConfigLoader implements IConfigLoader {
    */
   private isValidConfigStructure(config: ConfigFile): boolean {
     if (!config || typeof config !== 'object') {
-      return false;
+      return false
     }
 
     if (!config.version || typeof config.version !== 'string') {
-      return false;
+      return false
     }
 
     if (!Array.isArray(config.accounts)) {
-      return false;
+      return false
     }
 
-    return true;
+    return true
   }
 
   /**
@@ -341,11 +339,11 @@ export class ConfigLoader implements IConfigLoader {
    */
   private convertConfigToAccount(config: AccountConfig): Account {
     // Auto-detect platform if not specified or if mismatch
-    let platform = config.platform;
-    const detectedPlatform = this.platformDetector.detectPlatform(config.credentials);
+    let platform = config.platform
+    const detectedPlatform = this.platformDetector.detectPlatform(config.credentials)
 
     if (detectedPlatform && detectedPlatform !== platform) {
-      platform = detectedPlatform;
+      platform = detectedPlatform
     }
 
     return {
@@ -355,8 +353,8 @@ export class ConfigLoader implements IConfigLoader {
       credentials: config.credentials,
       enabled: config.enabled !== false, // Default to true
       metadata: config.metadata || {},
-      createdAt: new Date()
-    };
+      createdAt: new Date(),
+    }
   }
 
   /**
@@ -366,33 +364,33 @@ export class ConfigLoader implements IConfigLoader {
     // Note: In a real implementation, this would use fs.watch or chokidar
     // This is a simplified polling-based approach for demonstration
 
-    let lastModified = 0;
+    let lastModified = 0
 
     const checkFile = async () => {
       try {
-        const stats = await fs.stat(filePath);
-        const currentModified = stats.mtime.getTime();
+        const stats = await fs.stat(filePath)
+        const currentModified = stats.mtime.getTime()
 
         if (currentModified > lastModified && lastModified > 0) {
           // File has been modified
-          const result = await this.loadConfig(filePath);
+          const result = await this.loadConfig(filePath)
           if (result.success) {
-            callback(result.accounts);
+            callback(result.accounts)
           }
         }
 
-        lastModified = currentModified;
+        lastModified = currentModified
       } catch (error) {
         // File might have been deleted or is temporarily unavailable
         // In a real implementation, you'd handle this more gracefully
       }
-    };
+    }
 
     // Initial check
-    checkFile();
+    checkFile()
 
     // Set up periodic checking (every 100ms for demo - in practice use proper file watching)
-    const interval = setInterval(checkFile, 100);
+    const interval = setInterval(checkFile, 100)
 
     // Store interval for cleanup (in a real implementation)
     // this.watchIntervals.set(filePath, interval);
@@ -402,15 +400,15 @@ export class ConfigLoader implements IConfigLoader {
    * Get supported file formats
    */
   getSupportedFormats(): string[] {
-    return ['.json', '.yaml', '.yml'];
+    return ['.json', '.yaml', '.yml']
   }
 
   /**
    * Validate file format
    */
   isSupportedFormat(filePath: string): boolean {
-    const extension = path.extname(filePath).toLowerCase();
-    return this.getSupportedFormats().includes(extension);
+    const extension = path.extname(filePath).toLowerCase()
+    return this.getSupportedFormats().includes(extension)
   }
 
   /**
@@ -426,12 +424,12 @@ export class ConfigLoader implements IConfigLoader {
           name: 'Example Pacifica Account',
           credentials: {
             type: 'ed25519',
-            privateKey: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
+            privateKey: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
           },
           enabled: true,
           metadata: {
-            description: 'Example account for Pacifica platform'
-          }
+            description: 'Example account for Pacifica platform',
+          },
         },
         {
           id: 'example-binance-account',
@@ -440,18 +438,18 @@ export class ConfigLoader implements IConfigLoader {
           credentials: {
             type: 'hmac',
             apiKey: 'your-binance-api-key-here',
-            secretKey: 'your-binance-secret-key-here'
+            secretKey: 'your-binance-secret-key-here',
           },
           enabled: true,
           metadata: {
-            description: 'Example account for Binance platform'
-          }
-        }
+            description: 'Example account for Binance platform',
+          },
+        },
       ],
       metadata: {
         created: new Date().toISOString(),
-        description: 'Example credential configuration file'
-      }
-    };
+        description: 'Example credential configuration file',
+      },
+    }
   }
-}
+}

+ 8 - 2
src/core/credential-manager/ConfigValidator.ts

@@ -6,8 +6,14 @@
  * Supports JSON and YAML configuration formats.
  */
 
-import { Platform, Credentials, ConfigFile, AccountConfig } from '../../types/credential.js'
-import { CredentialManagerError, ErrorType } from '../../types/credential.js'
+import {
+  Platform,
+  Credentials,
+  ConfigFile,
+  AccountConfig,
+  CredentialManagerError,
+  ErrorType,
+} from '../../types/credential.js'
 
 // ============================================================================
 // Types and Interfaces

+ 166 - 177
src/core/credential-manager/CredentialManager.ts

@@ -14,25 +14,26 @@ import {
   Platform,
   CredentialErrorCode,
   CredentialManagerError,
-  PerformanceMetrics
-} from '@/types/credential';
-import { ConfigLoader } from './ConfigLoader';
-import { CredentialValidator } from './CredentialValidator';
-import { PlatformDetector } from './PlatformDetector';
-import { PacificaSigner } from './signers/PacificaSigner';
+  PerformanceMetrics,
+} from '@/types/credential'
+
+import { ConfigLoader } from './ConfigLoader'
+import { CredentialValidator } from './CredentialValidator'
+import { PlatformDetector } from './PlatformDetector'
+import { PacificaSigner } from './signers/PacificaSigner'
 
 /**
  * Main credential manager class
  */
 export class CredentialManager implements ICredentialManager {
-  private configLoader = new ConfigLoader();
-  private validator = new CredentialValidator();
-  private platformDetector = new PlatformDetector();
-  private accounts = new Map<string, Account>();
-  private signers = new Map<Platform, any>();
-  private isWatching = false;
-  private currentConfigPath?: string;
-  private metrics: PerformanceMetrics;
+  private configLoader = new ConfigLoader()
+  private validator = new CredentialValidator()
+  private platformDetector = new PlatformDetector()
+  private accounts = new Map<string, Account>()
+  private signers = new Map<Platform, any>()
+  private isWatching = false
+  private currentConfigPath?: string
+  private metrics: PerformanceMetrics
 
   constructor() {
     // Initialize performance metrics
@@ -51,66 +52,66 @@ export class CredentialManager implements ICredentialManager {
       averageVerifyTime: 0,
       memoryUsage: 0,
       accountCount: 0,
-      errorsByCode: Object.fromEntries(
-        Object.values(CredentialErrorCode).map(code => [code, 0])
-      ) as Record<CredentialErrorCode, number>,
+      errorsByCode: Object.fromEntries(Object.values(CredentialErrorCode).map(code => [code, 0])) as Record<
+        CredentialErrorCode,
+        number
+      >,
       lastResetAt: new Date(),
-      uptime: 0
-    };
+      uptime: 0,
+    }
 
     // Initialize signers
-    this.initializeSigners();
+    this.initializeSigners()
   }
 
   /**
    * Load configuration file
    */
   async loadConfig(filePath: string): Promise<LoadResult> {
-    const startTime = Date.now();
+    const startTime = Date.now()
 
     try {
       // Load configuration using ConfigLoader
-      const result = await this.configLoader.loadConfig(filePath);
+      const result = await this.configLoader.loadConfig(filePath)
 
       // Update metrics
-      const loadTime = Date.now() - startTime;
-      this.metrics.configLoadTime = loadTime;
+      const loadTime = Date.now() - startTime
+      this.metrics.configLoadTime = loadTime
 
       if (result.success) {
         // Clear existing accounts
-        this.accounts.clear();
+        this.accounts.clear()
 
         // Add loaded accounts to internal storage
         for (const account of result.accounts) {
-          this.accounts.set(account.id, account);
+          this.accounts.set(account.id, account)
         }
 
-        this.metrics.accountCount = this.accounts.size;
-        this.currentConfigPath = filePath;
+        this.metrics.accountCount = this.accounts.size
+        this.currentConfigPath = filePath
 
         // Validate all accounts have supported platforms
         for (const account of result.accounts) {
           if (!this.signers.has(account.platform)) {
-            this.recordError(CredentialErrorCode.PLATFORM_NOT_SUPPORTED);
-            console.warn(`Platform ${account.platform} not supported for account ${account.id}`);
+            this.recordError(CredentialErrorCode.PLATFORM_NOT_SUPPORTED)
+            console.warn(`Platform ${account.platform} not supported for account ${account.id}`)
           }
         }
       } else {
-        this.recordError(CredentialErrorCode.CONFIG_VALIDATION_FAILED);
+        this.recordError(CredentialErrorCode.CONFIG_VALIDATION_FAILED)
       }
 
-      return result;
-
+      return result
     } catch (error) {
-      const loadTime = Date.now() - startTime;
-      this.metrics.configLoadTime = loadTime;
-      this.recordError(CredentialErrorCode.CONFIG_NOT_FOUND);
+      const loadTime = Date.now() - startTime
+      this.metrics.configLoadTime = loadTime
+      this.recordError(CredentialErrorCode.CONFIG_NOT_FOUND)
 
       throw new CredentialManagerError(
         CredentialErrorCode.CONFIG_NOT_FOUND,
         `Failed to load configuration: ${error instanceof Error ? error.message : 'Unknown error'}`,
-        error
-      );
+        error,
+      )
     }
   }
 
@@ -121,36 +122,35 @@ export class CredentialManager implements ICredentialManager {
     try {
       if (this.isWatching && this.currentConfigPath !== filePath) {
         // Stop watching previous file
-        this.stopWatching();
+        this.stopWatching()
       }
 
       // Set up file watching
-      this.configLoader.watchConfig(filePath, (accounts) => {
-        const startTime = Date.now();
+      this.configLoader.watchConfig(filePath, accounts => {
+        const startTime = Date.now()
 
         // Update internal account storage
-        this.accounts.clear();
+        this.accounts.clear()
         for (const account of accounts) {
-          this.accounts.set(account.id, account);
+          this.accounts.set(account.id, account)
         }
 
-        this.metrics.accountCount = this.accounts.size;
-        this.metrics.configWatchLatency = Date.now() - startTime;
+        this.metrics.accountCount = this.accounts.size
+        this.metrics.configWatchLatency = Date.now() - startTime
 
         // Call user callback
-        callback(accounts);
-      });
-
-      this.isWatching = true;
-      this.currentConfigPath = filePath;
+        callback(accounts)
+      })
 
+      this.isWatching = true
+      this.currentConfigPath = filePath
     } catch (error) {
-      this.recordError(CredentialErrorCode.FILE_WATCH_FAILED);
+      this.recordError(CredentialErrorCode.FILE_WATCH_FAILED)
       throw new CredentialManagerError(
         CredentialErrorCode.FILE_WATCH_FAILED,
         `Failed to watch configuration file: ${error instanceof Error ? error.message : 'Unknown error'}`,
-        error
-      );
+        error,
+      )
     }
   }
 
@@ -159,11 +159,11 @@ export class CredentialManager implements ICredentialManager {
    */
   stopWatching(): void {
     try {
-      this.configLoader.stopWatching();
-      this.isWatching = false;
-      this.currentConfigPath = undefined;
+      this.configLoader.stopWatching()
+      this.isWatching = false
+      this.currentConfigPath = undefined
     } catch (error) {
-      console.warn('Error stopping configuration watching:', error);
+      console.warn('Error stopping configuration watching:', error)
     }
   }
 
@@ -172,108 +172,95 @@ export class CredentialManager implements ICredentialManager {
    */
   getAccount(accountId: string): Account | null {
     if (!accountId || typeof accountId !== 'string') {
-      return null;
+      return null
     }
 
-    return this.accounts.get(accountId) || null;
+    return this.accounts.get(accountId) || null
   }
 
   /**
    * List all accounts
    */
   listAccounts(): Account[] {
-    return Array.from(this.accounts.values());
+    return Array.from(this.accounts.values())
   }
 
   /**
    * Sign message with account
    */
   async sign(accountId: string, message: Uint8Array): Promise<SignResult> {
-    const startTime = Date.now();
-    this.metrics.signOperationsTotal++;
+    const startTime = Date.now()
+    this.metrics.signOperationsTotal++
 
     try {
       // Validate inputs
       if (!accountId || typeof accountId !== 'string') {
-        throw new CredentialManagerError(
-          CredentialErrorCode.ACCOUNT_NOT_FOUND,
-          'Invalid account ID'
-        );
+        throw new CredentialManagerError(CredentialErrorCode.ACCOUNT_NOT_FOUND, 'Invalid account ID')
       }
 
       if (!message || message.length === 0) {
-        throw new CredentialManagerError(
-          CredentialErrorCode.INVALID_MESSAGE,
-          'Message cannot be empty'
-        );
+        throw new CredentialManagerError(CredentialErrorCode.INVALID_MESSAGE, 'Message cannot be empty')
       }
 
       // Get account
-      const account = this.getAccount(accountId);
+      const account = this.getAccount(accountId)
       if (!account) {
-        throw new CredentialManagerError(
-          CredentialErrorCode.ACCOUNT_NOT_FOUND,
-          `Account not found: ${accountId}`
-        );
+        throw new CredentialManagerError(CredentialErrorCode.ACCOUNT_NOT_FOUND, `Account not found: ${accountId}`)
       }
 
       // Check if account is enabled
       if (!account.enabled) {
-        throw new CredentialManagerError(
-          CredentialErrorCode.ACCOUNT_DISABLED,
-          `Account is disabled: ${accountId}`
-        );
+        throw new CredentialManagerError(CredentialErrorCode.ACCOUNT_DISABLED, `Account is disabled: ${accountId}`)
       }
 
       // Get appropriate signer
-      const signer = this.signers.get(account.platform);
+      const signer = this.signers.get(account.platform)
       if (!signer) {
         throw new CredentialManagerError(
           CredentialErrorCode.PLATFORM_NOT_SUPPORTED,
-          `Platform not supported: ${account.platform}`
-        );
+          `Platform not supported: ${account.platform}`,
+        )
       }
 
       // Perform signing
-      const signature = await signer.sign(message, account.credentials);
+      const signature = await signer.sign(message, account.credentials)
 
-      const duration = Date.now() - startTime;
-      this.updateSigningMetrics(true, duration);
+      const duration = Date.now() - startTime
+      this.updateSigningMetrics(true, duration)
 
       // Update account last used time
-      account.lastUsed = new Date();
+      account.lastUsed = new Date()
 
       return {
         success: true,
         signature,
         algorithm: this.getAlgorithmForPlatform(account.platform),
         timestamp: new Date(),
-        duration
-      };
-
+        duration,
+      }
     } catch (error) {
-      const duration = Date.now() - startTime;
-      this.updateSigningMetrics(false, duration);
+      const duration = Date.now() - startTime
+      this.updateSigningMetrics(false, duration)
 
       if (error instanceof CredentialManagerError) {
-        this.recordError(error.code);
+        this.recordError(error.code)
         return {
           success: false,
           algorithm: this.getAlgorithmForPlatform(Platform.PACIFICA), // Default
           timestamp: new Date(),
           duration,
-          error: error.message
-        };
+          error: error.message,
+        }
       }
 
-      this.recordError(CredentialErrorCode.SIGNING_FAILED);
+      this.recordError(CredentialErrorCode.SIGNING_FAILED)
       return {
         success: false,
         algorithm: this.getAlgorithmForPlatform(Platform.PACIFICA), // Default
         timestamp: new Date(),
         duration,
-        error: `Signing failed: ${error instanceof Error ? error.message : 'Unknown error'}`
-      };
+        error: `Signing failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
+      }
     }
   }
 
@@ -281,51 +268,50 @@ export class CredentialManager implements ICredentialManager {
    * Verify signature
    */
   async verify(accountId: string, message: Uint8Array, signature: string): Promise<boolean> {
-    const startTime = Date.now();
-    this.metrics.verifyOperationsTotal++;
+    const startTime = Date.now()
+    this.metrics.verifyOperationsTotal++
 
     try {
       // Validate inputs
       if (!accountId || !message || !signature) {
-        this.metrics.verifyOperationsFailed++;
-        return false;
+        this.metrics.verifyOperationsFailed++
+        return false
       }
 
       // Get account
-      const account = this.getAccount(accountId);
+      const account = this.getAccount(accountId)
       if (!account) {
-        this.metrics.verifyOperationsFailed++;
-        return false;
+        this.metrics.verifyOperationsFailed++
+        return false
       }
 
       // Get appropriate signer
-      const signer = this.signers.get(account.platform);
+      const signer = this.signers.get(account.platform)
       if (!signer) {
-        this.metrics.verifyOperationsFailed++;
-        return false;
+        this.metrics.verifyOperationsFailed++
+        return false
       }
 
       // Get public key for verification
-      let publicKey: string;
+      let publicKey: string
       try {
-        publicKey = await this.getPublicKeyForAccount(account);
+        publicKey = await this.getPublicKeyForAccount(account)
       } catch (error) {
-        this.metrics.verifyOperationsFailed++;
-        return false;
+        this.metrics.verifyOperationsFailed++
+        return false
       }
 
       // Perform verification
-      const isValid = await signer.verify(message, signature, publicKey);
+      const isValid = await signer.verify(message, signature, publicKey)
 
-      const duration = Date.now() - startTime;
-      this.updateVerificationMetrics(isValid, duration);
-
-      return isValid;
+      const duration = Date.now() - startTime
+      this.updateVerificationMetrics(isValid, duration)
 
+      return isValid
     } catch (error) {
-      const duration = Date.now() - startTime;
-      this.updateVerificationMetrics(false, duration);
-      return false;
+      const duration = Date.now() - startTime
+      this.updateVerificationMetrics(false, duration)
+      return false
     }
   }
 
@@ -334,14 +320,14 @@ export class CredentialManager implements ICredentialManager {
    */
   getMetrics(): PerformanceMetrics {
     // Update uptime
-    this.metrics.uptime = Date.now() - this.metrics.lastResetAt.getTime();
+    this.metrics.uptime = Date.now() - this.metrics.lastResetAt.getTime()
 
     // Update memory usage if available
     if (process.memoryUsage) {
-      this.metrics.memoryUsage = process.memoryUsage().heapUsed;
+      this.metrics.memoryUsage = process.memoryUsage().heapUsed
     }
 
-    return { ...this.metrics };
+    return { ...this.metrics }
   }
 
   /**
@@ -365,26 +351,26 @@ export class CredentialManager implements ICredentialManager {
       accountCount: this.accounts.size,
       errorsByCode: {},
       lastResetAt: new Date(),
-      uptime: 0
-    };
+      uptime: 0,
+    }
   }
 
   /**
    * Health check
    */
   async healthCheck(): Promise<{
-    healthy: boolean;
+    healthy: boolean
     components: {
-      configLoader: boolean;
-      accounts: boolean;
-      signers: Record<Platform, boolean>;
-    };
+      configLoader: boolean
+      accounts: boolean
+      signers: Record<Platform, boolean>
+    }
     performance: {
-      configLoadTime: number;
-      averageSignTime: number;
-      memoryUsage: number;
-    };
-    timestamp: Date;
+      configLoadTime: number
+      averageSignTime: number
+      memoryUsage: number
+    }
+    timestamp: Date
   }> {
     const health = {
       healthy: true,
@@ -394,24 +380,25 @@ export class CredentialManager implements ICredentialManager {
         signers: {
           [Platform.PACIFICA]: this.signers.has(Platform.PACIFICA),
           [Platform.ASTER]: this.signers.has(Platform.ASTER),
-          [Platform.BINANCE]: this.signers.has(Platform.BINANCE)
-        }
+          [Platform.BINANCE]: this.signers.has(Platform.BINANCE),
+        },
       },
       performance: {
         configLoadTime: this.metrics.configLoadTime,
         averageSignTime: this.metrics.averageSignTime,
-        memoryUsage: this.metrics.memoryUsage
+        memoryUsage: this.metrics.memoryUsage,
       },
-      timestamp: new Date()
-    };
+      timestamp: new Date(),
+    }
 
     // Check overall health
-    health.healthy = health.components.configLoader &&
-                    Object.values(health.components.signers).some(Boolean) &&
-                    health.performance.configLoadTime < 100 &&
-                    health.performance.averageSignTime < 50;
+    health.healthy =
+      health.components.configLoader &&
+      Object.values(health.components.signers).some(Boolean) &&
+      health.performance.configLoadTime < 100 &&
+      health.performance.averageSignTime < 50
 
-    return health;
+    return health
   }
 
   /**
@@ -419,7 +406,7 @@ export class CredentialManager implements ICredentialManager {
    */
   private initializeSigners(): void {
     // Initialize Pacifica signer
-    this.signers.set(Platform.PACIFICA, new PacificaSigner());
+    this.signers.set(Platform.PACIFICA, new PacificaSigner())
 
     // TODO: Initialize other signers when implemented
     // this.signers.set(Platform.BINANCE, new BinanceSigner());
@@ -432,13 +419,13 @@ export class CredentialManager implements ICredentialManager {
   private getAlgorithmForPlatform(platform: Platform): string {
     switch (platform) {
       case Platform.PACIFICA:
-        return 'ed25519';
+        return 'ed25519'
       case Platform.ASTER:
-        return 'eip191';
+        return 'eip191'
       case Platform.BINANCE:
-        return 'hmac-sha256';
+        return 'hmac-sha256'
       default:
-        return 'unknown';
+        return 'unknown'
     }
   }
 
@@ -450,24 +437,24 @@ export class CredentialManager implements ICredentialManager {
       case Platform.PACIFICA:
         if (account.credentials.type === 'ed25519' && 'privateKey' in account.credentials) {
           // Derive public key from private key
-          const { PacificaKeyUtils } = await import('./signers/PacificaSigner');
-          return PacificaKeyUtils.derivePublicKey(account.credentials.privateKey);
+          const { PacificaKeyUtils } = await import('./signers/PacificaSigner')
+          return PacificaKeyUtils.derivePublicKey(account.credentials.privateKey)
         }
-        break;
+        break
 
       case Platform.ASTER:
         // TODO: Implement Aster public key derivation
-        break;
+        break
 
       case Platform.BINANCE:
         // HMAC doesn't use public keys for verification
-        return '';
+        return ''
     }
 
     throw new CredentialManagerError(
       CredentialErrorCode.ACCOUNT_INVALID_CREDENTIALS,
-      `Cannot derive public key for platform ${account.platform}`
-    );
+      `Cannot derive public key for platform ${account.platform}`,
+    )
   }
 
   /**
@@ -475,19 +462,20 @@ export class CredentialManager implements ICredentialManager {
    */
   private updateSigningMetrics(success: boolean, duration: number): void {
     if (success) {
-      this.metrics.signOperationsSuccess++;
+      this.metrics.signOperationsSuccess++
     } else {
-      this.metrics.signOperationsFailed++;
+      this.metrics.signOperationsFailed++
     }
 
     // Update timing metrics
-    this.metrics.maxSignTime = Math.max(this.metrics.maxSignTime, duration);
-    this.metrics.minSignTime = Math.min(this.metrics.minSignTime, duration);
+    this.metrics.maxSignTime = Math.max(this.metrics.maxSignTime, duration)
+    this.metrics.minSignTime = Math.min(this.metrics.minSignTime, duration)
 
     // Calculate rolling average
-    const totalSuccessfulSigns = this.metrics.signOperationsSuccess;
+    const totalSuccessfulSigns = this.metrics.signOperationsSuccess
     if (totalSuccessfulSigns > 0) {
-      this.metrics.averageSignTime = ((this.metrics.averageSignTime * (totalSuccessfulSigns - 1)) + duration) / totalSuccessfulSigns;
+      this.metrics.averageSignTime =
+        (this.metrics.averageSignTime * (totalSuccessfulSigns - 1) + duration) / totalSuccessfulSigns
     }
   }
 
@@ -496,15 +484,16 @@ export class CredentialManager implements ICredentialManager {
    */
   private updateVerificationMetrics(success: boolean, duration: number): void {
     if (success) {
-      this.metrics.verifyOperationsSuccess++;
+      this.metrics.verifyOperationsSuccess++
     } else {
-      this.metrics.verifyOperationsFailed++;
+      this.metrics.verifyOperationsFailed++
     }
 
     // Calculate rolling average for verification time
-    const totalVerifications = this.metrics.verifyOperationsTotal;
+    const totalVerifications = this.metrics.verifyOperationsTotal
     if (totalVerifications > 0) {
-      this.metrics.averageVerifyTime = ((this.metrics.averageVerifyTime * (totalVerifications - 1)) + duration) / totalVerifications;
+      this.metrics.averageVerifyTime =
+        (this.metrics.averageVerifyTime * (totalVerifications - 1) + duration) / totalVerifications
     }
   }
 
@@ -512,40 +501,40 @@ export class CredentialManager implements ICredentialManager {
    * Record error in metrics
    */
   private recordError(errorCode: CredentialErrorCode): void {
-    this.metrics.errorsByCode[errorCode] = (this.metrics.errorsByCode[errorCode] || 0) + 1;
+    this.metrics.errorsByCode[errorCode] = (this.metrics.errorsByCode[errorCode] || 0) + 1
   }
 
   /**
    * Validate account credentials
    */
   validateAccount(accountId: string): {
-    isValid: boolean;
-    errors: string[];
-    warnings: string[];
+    isValid: boolean
+    errors: string[]
+    warnings: string[]
   } {
-    const account = this.getAccount(accountId);
+    const account = this.getAccount(accountId)
     if (!account) {
       return {
         isValid: false,
         errors: [`Account not found: ${accountId}`],
-        warnings: []
-      };
+        warnings: [],
+      }
     }
 
-    return this.validator.validateAccountConfig(account);
+    return this.validator.validateAccountConfig(account)
   }
 
   /**
    * Get supported platforms
    */
   getSupportedPlatforms(): Platform[] {
-    return Array.from(this.signers.keys());
+    return Array.from(this.signers.keys())
   }
 
   /**
    * Check if platform is supported
    */
   isPlatformSupported(platform: Platform): boolean {
-    return this.signers.has(platform);
+    return this.signers.has(platform)
   }
-}
+}

+ 181 - 183
src/core/credential-manager/CredentialValidator.ts

@@ -13,18 +13,18 @@ import {
   HmacCredentials,
   AccountConfig,
   CredentialErrorCode,
-  CredentialManagerError
-} from '@/types/credential';
+  CredentialManagerError,
+} from '@/types/credential'
 
 /**
  * Validation result interface
  */
 export interface ValidationResult {
-  isValid: boolean;
-  errors: string[];
-  warnings: string[];
-  platform?: Platform;
-  credentialType?: string;
+  isValid: boolean
+  errors: string[]
+  warnings: string[]
+  platform?: Platform
+  credentialType?: string
 }
 
 /**
@@ -40,73 +40,73 @@ export class CredentialValidator {
     const result: ValidationResult = {
       isValid: true,
       errors: [],
-      warnings: []
-    };
+      warnings: [],
+    }
 
     // Basic structure validation
     if (!config || typeof config !== 'object') {
-      result.errors.push('Account configuration must be an object');
-      result.isValid = false;
-      return result;
+      result.errors.push('Account configuration must be an object')
+      result.isValid = false
+      return result
     }
 
     // Required fields
     if (!config.id || typeof config.id !== 'string') {
-      result.errors.push('Account ID is required and must be a string');
-      result.isValid = false;
+      result.errors.push('Account ID is required and must be a string')
+      result.isValid = false
     } else if (config.id.length === 0 || config.id.trim().length === 0) {
-      result.errors.push('Account ID cannot be empty');
-      result.isValid = false;
+      result.errors.push('Account ID cannot be empty')
+      result.isValid = false
     } else if (config.id.length > 100) {
-      result.errors.push('Account ID cannot exceed 100 characters');
-      result.isValid = false;
+      result.errors.push('Account ID cannot exceed 100 characters')
+      result.isValid = false
     }
 
     // Platform validation
     if (!config.platform) {
-      result.errors.push('Platform is required');
-      result.isValid = false;
+      result.errors.push('Platform is required')
+      result.isValid = false
     } else if (!Object.values(Platform).includes(config.platform)) {
-      result.errors.push(`Invalid platform: ${config.platform}. Must be one of: ${Object.values(Platform).join(', ')}`);
-      result.isValid = false;
+      result.errors.push(`Invalid platform: ${config.platform}. Must be one of: ${Object.values(Platform).join(', ')}`)
+      result.isValid = false
     } else {
-      result.platform = config.platform;
+      result.platform = config.platform
     }
 
     // Name validation
     if (!config.name || typeof config.name !== 'string') {
-      result.errors.push('Account name is required and must be a string');
-      result.isValid = false;
+      result.errors.push('Account name is required and must be a string')
+      result.isValid = false
     } else if (config.name.trim().length === 0) {
-      result.errors.push('Account name cannot be empty');
-      result.isValid = false;
+      result.errors.push('Account name cannot be empty')
+      result.isValid = false
     }
 
     // Credentials validation
     if (!config.credentials) {
-      result.errors.push('Credentials are required');
-      result.isValid = false;
+      result.errors.push('Credentials are required')
+      result.isValid = false
     } else {
-      const credentialValidation = this.validateCredentials(config.credentials, config.platform);
-      result.errors.push(...credentialValidation.errors);
-      result.warnings.push(...credentialValidation.warnings);
-      result.credentialType = credentialValidation.credentialType;
+      const credentialValidation = this.validateCredentials(config.credentials, config.platform)
+      result.errors.push(...credentialValidation.errors)
+      result.warnings.push(...credentialValidation.warnings)
+      result.credentialType = credentialValidation.credentialType
 
       if (!credentialValidation.isValid) {
-        result.isValid = false;
+        result.isValid = false
       }
     }
 
     // Optional field validation
     if (config.enabled !== undefined && typeof config.enabled !== 'boolean') {
-      result.warnings.push('Account enabled flag should be a boolean, defaulting to true');
+      result.warnings.push('Account enabled flag should be a boolean, defaulting to true')
     }
 
     if (config.metadata !== undefined && typeof config.metadata !== 'object') {
-      result.warnings.push('Account metadata should be an object, ignoring');
+      result.warnings.push('Account metadata should be an object, ignoring')
     }
 
-    return result;
+    return result
   }
 
   /**
@@ -119,52 +119,58 @@ export class CredentialValidator {
     const result: ValidationResult = {
       isValid: true,
       errors: [],
-      warnings: []
-    };
+      warnings: [],
+    }
 
     if (!credentials || typeof credentials !== 'object') {
-      result.errors.push('Credentials must be an object');
-      result.isValid = false;
-      return result;
+      result.errors.push('Credentials must be an object')
+      result.isValid = false
+      return result
     }
 
     if (!credentials.type || typeof credentials.type !== 'string') {
-      result.errors.push('Credential type is required');
-      result.isValid = false;
-      return result;
+      result.errors.push('Credential type is required')
+      result.isValid = false
+      return result
     }
 
-    result.credentialType = credentials.type;
+    result.credentialType = credentials.type
 
     // Platform-specific validation
     switch (credentials.type) {
       case 'ed25519':
-        this.validateEd25519Credentials(credentials, result);
+        this.validateEd25519Credentials(credentials, result)
         if (platform && platform !== Platform.PACIFICA) {
-          result.warnings.push(`Ed25519 credentials typically used with Pacifica platform, but account platform is ${platform}`);
+          result.warnings.push(
+            `Ed25519 credentials typically used with Pacifica platform, but account platform is ${platform}`,
+          )
         }
-        break;
+        break
 
       case 'eip191':
-        this.validateEip191Credentials(credentials, result);
+        this.validateEip191Credentials(credentials, result)
         if (platform && platform !== Platform.ASTER) {
-          result.warnings.push(`EIP-191 credentials typically used with Aster platform, but account platform is ${platform}`);
+          result.warnings.push(
+            `EIP-191 credentials typically used with Aster platform, but account platform is ${platform}`,
+          )
         }
-        break;
+        break
 
       case 'hmac':
-        this.validateHmacCredentials(credentials, result);
+        this.validateHmacCredentials(credentials, result)
         if (platform && platform !== Platform.BINANCE) {
-          result.warnings.push(`HMAC credentials typically used with Binance platform, but account platform is ${platform}`);
+          result.warnings.push(
+            `HMAC credentials typically used with Binance platform, but account platform is ${platform}`,
+          )
         }
-        break;
+        break
 
       default:
-        result.errors.push(`Unsupported credential type: ${credentials.type}`);
-        result.isValid = false;
+        result.errors.push(`Unsupported credential type: ${credentials.type}`)
+        result.isValid = false
     }
 
-    return result;
+    return result
   }
 
   /**
@@ -173,58 +179,54 @@ export class CredentialValidator {
   private validateEd25519Credentials(credentials: any, result: ValidationResult): void {
     // Private key validation
     if (!credentials.privateKey) {
-      result.errors.push('Ed25519 credentials require a privateKey');
-      result.isValid = false;
-      return;
+      result.errors.push('Ed25519 credentials require a privateKey')
+      result.isValid = false
+      return
     }
 
     if (typeof credentials.privateKey !== 'string') {
-      result.errors.push('Ed25519 privateKey must be a string');
-      result.isValid = false;
-      return;
+      result.errors.push('Ed25519 privateKey must be a string')
+      result.isValid = false
+      return
     }
 
-    const privateKey = credentials.privateKey.toLowerCase();
+    const privateKey = credentials.privateKey.toLowerCase()
 
     // Check format: 64 hex characters (32 bytes)
     if (!/^[0-9a-f]{64}$/.test(privateKey)) {
-      result.errors.push('Ed25519 privateKey must be 64 hexadecimal characters (32 bytes)');
-      result.isValid = false;
+      result.errors.push('Ed25519 privateKey must be 64 hexadecimal characters (32 bytes)')
+      result.isValid = false
     }
 
     // Security checks
     if (privateKey === '0'.repeat(64)) {
-      result.errors.push('Ed25519 privateKey cannot be all zeros');
-      result.isValid = false;
+      result.errors.push('Ed25519 privateKey cannot be all zeros')
+      result.isValid = false
     }
 
     if (privateKey === 'f'.repeat(64)) {
-      result.errors.push('Ed25519 privateKey cannot be all ones');
-      result.isValid = false;
+      result.errors.push('Ed25519 privateKey cannot be all ones')
+      result.isValid = false
     }
 
     // Check for weak keys (common patterns)
-    const weakPatterns = [
-      '1'.repeat(64),
-      '123456789abcdef'.repeat(4),
-      'deadbeef'.repeat(8)
-    ];
+    const weakPatterns = ['1'.repeat(64), '123456789abcdef'.repeat(4), 'deadbeef'.repeat(8)]
 
     for (const pattern of weakPatterns) {
       if (privateKey === pattern) {
-        result.warnings.push('Ed25519 privateKey appears to be a weak/test key');
-        break;
+        result.warnings.push('Ed25519 privateKey appears to be a weak/test key')
+        break
       }
     }
 
     // Public key validation (if provided)
     if (credentials.publicKey) {
       if (typeof credentials.publicKey !== 'string') {
-        result.warnings.push('Ed25519 publicKey should be a string');
+        result.warnings.push('Ed25519 publicKey should be a string')
       } else {
         // Base58 format validation (typical for Pacifica)
         if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(credentials.publicKey)) {
-          result.warnings.push('Ed25519 publicKey format may be invalid (expected base58)');
+          result.warnings.push('Ed25519 publicKey format may be invalid (expected base58)')
         }
       }
     }
@@ -236,58 +238,58 @@ export class CredentialValidator {
   private validateEip191Credentials(credentials: any, result: ValidationResult): void {
     // Private key validation
     if (!credentials.privateKey) {
-      result.errors.push('EIP-191 credentials require a privateKey');
-      result.isValid = false;
-      return;
+      result.errors.push('EIP-191 credentials require a privateKey')
+      result.isValid = false
+      return
     }
 
     if (typeof credentials.privateKey !== 'string') {
-      result.errors.push('EIP-191 privateKey must be a string');
-      result.isValid = false;
-      return;
+      result.errors.push('EIP-191 privateKey must be a string')
+      result.isValid = false
+      return
     }
 
-    const privateKey = credentials.privateKey.toLowerCase();
+    const privateKey = credentials.privateKey.toLowerCase()
 
     // Check format: 0x + 64 hex characters
     if (!/^0x[0-9a-f]{64}$/.test(privateKey)) {
-      result.errors.push('EIP-191 privateKey must be 0x followed by 64 hexadecimal characters');
-      result.isValid = false;
+      result.errors.push('EIP-191 privateKey must be 0x followed by 64 hexadecimal characters')
+      result.isValid = false
     }
 
     // Security checks
     if (privateKey === '0x' + '0'.repeat(64)) {
-      result.errors.push('EIP-191 privateKey cannot be all zeros');
-      result.isValid = false;
+      result.errors.push('EIP-191 privateKey cannot be all zeros')
+      result.isValid = false
     }
 
     if (privateKey === '0x' + 'f'.repeat(64)) {
-      result.errors.push('EIP-191 privateKey cannot be all ones');
-      result.isValid = false;
+      result.errors.push('EIP-191 privateKey cannot be all ones')
+      result.isValid = false
     }
 
     // Check for weak keys
     const weakPatterns = [
       '0x' + '1'.repeat(64),
       '0x' + '123456789abcdef0'.repeat(4),
-      '0x' + 'deadbeefdeadbeef'.repeat(4)
-    ];
+      '0x' + 'deadbeefdeadbeef'.repeat(4),
+    ]
 
     for (const pattern of weakPatterns) {
       if (privateKey === pattern) {
-        result.warnings.push('EIP-191 privateKey appears to be a weak/test key');
-        break;
+        result.warnings.push('EIP-191 privateKey appears to be a weak/test key')
+        break
       }
     }
 
     // Address validation (if provided)
     if (credentials.address) {
       if (typeof credentials.address !== 'string') {
-        result.warnings.push('EIP-191 address should be a string');
+        result.warnings.push('EIP-191 address should be a string')
       } else {
-        const address = credentials.address.toLowerCase();
+        const address = credentials.address.toLowerCase()
         if (!/^0x[0-9a-f]{40}$/.test(address)) {
-          result.warnings.push('EIP-191 address format may be invalid (expected 0x + 40 hex chars)');
+          result.warnings.push('EIP-191 address format may be invalid (expected 0x + 40 hex chars)')
         }
       }
     }
@@ -295,11 +297,11 @@ export class CredentialValidator {
     // Public key validation (if provided)
     if (credentials.publicKey) {
       if (typeof credentials.publicKey !== 'string') {
-        result.warnings.push('EIP-191 publicKey should be a string');
+        result.warnings.push('EIP-191 publicKey should be a string')
       } else {
-        const publicKey = credentials.publicKey.toLowerCase();
+        const publicKey = credentials.publicKey.toLowerCase()
         if (!/^0x[0-9a-f]{128}$/.test(publicKey)) {
-          result.warnings.push('EIP-191 publicKey format may be invalid (expected 0x + 128 hex chars for uncompressed)');
+          result.warnings.push('EIP-191 publicKey format may be invalid (expected 0x + 128 hex chars for uncompressed)')
         }
       }
     }
@@ -311,66 +313,60 @@ export class CredentialValidator {
   private validateHmacCredentials(credentials: any, result: ValidationResult): void {
     // API key validation
     if (!credentials.apiKey) {
-      result.errors.push('HMAC credentials require an apiKey');
-      result.isValid = false;
+      result.errors.push('HMAC credentials require an apiKey')
+      result.isValid = false
     } else if (typeof credentials.apiKey !== 'string') {
-      result.errors.push('HMAC apiKey must be a string');
-      result.isValid = false;
+      result.errors.push('HMAC apiKey must be a string')
+      result.isValid = false
     } else if (credentials.apiKey.length < 16) {
-      result.errors.push('HMAC apiKey must be at least 16 characters');
-      result.isValid = false;
+      result.errors.push('HMAC apiKey must be at least 16 characters')
+      result.isValid = false
     } else if (credentials.apiKey.length > 128) {
-      result.warnings.push('HMAC apiKey is unusually long (>128 characters)');
+      result.warnings.push('HMAC apiKey is unusually long (>128 characters)')
     }
 
     // Secret key validation
     if (!credentials.secretKey) {
-      result.errors.push('HMAC credentials require a secretKey');
-      result.isValid = false;
+      result.errors.push('HMAC credentials require a secretKey')
+      result.isValid = false
     } else if (typeof credentials.secretKey !== 'string') {
-      result.errors.push('HMAC secretKey must be a string');
-      result.isValid = false;
+      result.errors.push('HMAC secretKey must be a string')
+      result.isValid = false
     } else if (credentials.secretKey.length < 16) {
-      result.errors.push('HMAC secretKey must be at least 16 characters');
-      result.isValid = false;
+      result.errors.push('HMAC secretKey must be at least 16 characters')
+      result.isValid = false
     } else if (credentials.secretKey.length > 128) {
-      result.warnings.push('HMAC secretKey is unusually long (>128 characters)');
+      result.warnings.push('HMAC secretKey is unusually long (>128 characters)')
     }
 
     // Security checks
     if (credentials.apiKey && credentials.secretKey) {
       if (credentials.apiKey === credentials.secretKey) {
-        result.errors.push('HMAC apiKey and secretKey cannot be the same');
-        result.isValid = false;
+        result.errors.push('HMAC apiKey and secretKey cannot be the same')
+        result.isValid = false
       }
 
       // Check for test/demo keys
-      const testPatterns = [
-        'test',
-        'demo',
-        'sample',
-        'example',
-        '123456',
-        'abcdef'
-      ];
+      const testPatterns = ['test', 'demo', 'sample', 'example', '123456', 'abcdef']
 
       for (const pattern of testPatterns) {
-        if (credentials.apiKey.toLowerCase().includes(pattern) ||
-            credentials.secretKey.toLowerCase().includes(pattern)) {
-          result.warnings.push('HMAC credentials appear to be test/demo keys');
-          break;
+        if (
+          credentials.apiKey.toLowerCase().includes(pattern) ||
+          credentials.secretKey.toLowerCase().includes(pattern)
+        ) {
+          result.warnings.push('HMAC credentials appear to be test/demo keys')
+          break
         }
       }
 
       // Binance-specific format check
-      const binanceApiKeyPattern = /^[A-Za-z0-9]{64}$/;
-      const binanceSecretKeyPattern = /^[A-Za-z0-9]{64}$/;
+      const binanceApiKeyPattern = /^[A-Za-z0-9]{64}$/
+      const binanceSecretKeyPattern = /^[A-Za-z0-9]{64}$/
 
-      if (binanceApiKeyPattern.test(credentials.apiKey) &&
-          binanceSecretKeyPattern.test(credentials.secretKey)) {
+      if (binanceApiKeyPattern.test(credentials.apiKey) && binanceSecretKeyPattern.test(credentials.secretKey)) {
         // Valid Binance format
       } else {
-        result.warnings.push('HMAC credentials may not be in standard Binance format');
+        result.warnings.push('HMAC credentials may not be in standard Binance format')
       }
     }
   }
@@ -382,44 +378,46 @@ export class CredentialValidator {
    */
   validateAccountConfigs(configs: any[]): ValidationResult[] {
     if (!Array.isArray(configs)) {
-      return [{
-        isValid: false,
-        errors: ['Account configurations must be an array'],
-        warnings: []
-      }];
+      return [
+        {
+          isValid: false,
+          errors: ['Account configurations must be an array'],
+          warnings: [],
+        },
+      ]
     }
 
-    const results = configs.map(config => this.validateAccountConfig(config));
+    const results = configs.map(config => this.validateAccountConfig(config))
 
     // Check for duplicate IDs
-    const ids = new Set<string>();
-    const duplicateIds = new Set<string>();
+    const ids = new Set<string>()
+    const duplicateIds = new Set<string>()
 
     for (let i = 0; i < configs.length; i++) {
-      const config = configs[i];
+      const config = configs[i]
       if (config && config.id) {
         if (ids.has(config.id)) {
-          duplicateIds.add(config.id);
-          results[i].errors.push(`Duplicate account ID: ${config.id}`);
-          results[i].isValid = false;
+          duplicateIds.add(config.id)
+          results[i].errors.push(`Duplicate account ID: ${config.id}`)
+          results[i].isValid = false
         } else {
-          ids.add(config.id);
+          ids.add(config.id)
         }
       }
     }
 
     // Mark all instances of duplicate IDs as invalid
     for (let i = 0; i < configs.length; i++) {
-      const config = configs[i];
+      const config = configs[i]
       if (config && config.id && duplicateIds.has(config.id)) {
         if (!results[i].errors.includes(`Duplicate account ID: ${config.id}`)) {
-          results[i].errors.push(`Duplicate account ID: ${config.id}`);
-          results[i].isValid = false;
+          results[i].errors.push(`Duplicate account ID: ${config.id}`)
+          results[i].isValid = false
         }
       }
     }
 
-    return results;
+    return results
   }
 
   /**
@@ -428,17 +426,17 @@ export class CredentialValidator {
    * @returns Detailed validation report
    */
   generateValidationReport(configs: any[]): {
-    isValid: boolean;
-    totalAccounts: number;
-    validAccounts: number;
-    invalidAccounts: number;
-    platformCounts: Record<Platform, number>;
-    credentialTypeCounts: Record<string, number>;
-    globalErrors: string[];
-    globalWarnings: string[];
-    accountResults: ValidationResult[];
+    isValid: boolean
+    totalAccounts: number
+    validAccounts: number
+    invalidAccounts: number
+    platformCounts: Record<Platform, number>
+    credentialTypeCounts: Record<string, number>
+    globalErrors: string[]
+    globalWarnings: string[]
+    accountResults: ValidationResult[]
   } {
-    const results = this.validateAccountConfigs(configs);
+    const results = this.validateAccountConfigs(configs)
 
     const report = {
       isValid: results.every(r => r.isValid),
@@ -448,46 +446,46 @@ export class CredentialValidator {
       platformCounts: {
         [Platform.PACIFICA]: 0,
         [Platform.ASTER]: 0,
-        [Platform.BINANCE]: 0
+        [Platform.BINANCE]: 0,
       },
       credentialTypeCounts: {} as Record<string, number>,
       globalErrors: [] as string[],
       globalWarnings: [] as string[],
-      accountResults: results
-    };
+      accountResults: results,
+    }
 
     // Count platforms and credential types
     for (let i = 0; i < configs.length; i++) {
-      const config = configs[i];
-      const result = results[i];
+      const config = configs[i]
+      const result = results[i]
 
       if (result.platform) {
-        report.platformCounts[result.platform]++;
+        report.platformCounts[result.platform]++
       }
 
       if (result.credentialType) {
         report.credentialTypeCounts[result.credentialType] =
-          (report.credentialTypeCounts[result.credentialType] || 0) + 1;
+          (report.credentialTypeCounts[result.credentialType] || 0) + 1
       }
     }
 
     // Global warnings
     if (report.totalAccounts === 0) {
-      report.globalWarnings.push('No accounts configured');
+      report.globalWarnings.push('No accounts configured')
     }
 
     if (report.invalidAccounts > 0) {
-      report.globalErrors.push(`${report.invalidAccounts} account(s) have validation errors`);
+      report.globalErrors.push(`${report.invalidAccounts} account(s) have validation errors`)
     }
 
-    const totalPlatforms = Object.values(report.platformCounts).filter(count => count > 0).length;
+    const totalPlatforms = Object.values(report.platformCounts).filter(count => count > 0).length
     if (totalPlatforms === 0) {
-      report.globalWarnings.push('No valid platforms detected');
+      report.globalWarnings.push('No valid platforms detected')
     } else if (totalPlatforms === 1) {
-      report.globalWarnings.push('Only one platform type configured');
+      report.globalWarnings.push('Only one platform type configured')
     }
 
-    return report;
+    return report
   }
 
   /**
@@ -497,25 +495,25 @@ export class CredentialValidator {
    */
   sanitizeCredentials(credentials: any): any {
     if (!credentials || typeof credentials !== 'object') {
-      return credentials;
+      return credentials
     }
 
-    const sanitized = { ...credentials };
+    const sanitized = { ...credentials }
 
     // Remove or mask sensitive fields
     if (sanitized.privateKey) {
-      sanitized.privateKey = '***REDACTED***';
+      sanitized.privateKey = '***REDACTED***'
     }
 
     if (sanitized.secretKey) {
-      sanitized.secretKey = '***REDACTED***';
+      sanitized.secretKey = '***REDACTED***'
     }
 
     if (sanitized.apiKey) {
       // Show first 8 characters for debugging
-      sanitized.apiKey = sanitized.apiKey.substring(0, 8) + '***REDACTED***';
+      sanitized.apiKey = sanitized.apiKey.substring(0, 8) + '***REDACTED***'
     }
 
-    return sanitized;
+    return sanitized
   }
-}
+}

+ 176 - 176
src/core/credential-manager/ErrorHandler.ts

@@ -6,48 +6,49 @@
  * strategies, and audit trail functionality.
  */
 
-import { EventEmitter } from 'events';
-import { CredentialManagerError, ErrorType } from '../../types/credential.js';
+import { EventEmitter } from 'events'
+
+import { CredentialManagerError, ErrorType } from '../../types/credential.js'
 
 // ============================================================================
 // Types and Interfaces
 // ============================================================================
 
 export interface LogEntry {
-  timestamp: Date;
-  level: LogLevel;
-  message: string;
-  component: string;
-  operation?: string;
-  accountId?: string;
-  platform?: string;
-  error?: Error;
-  metadata?: Record<string, any>;
-  correlationId?: string;
+  timestamp: Date
+  level: LogLevel
+  message: string
+  component: string
+  operation?: string
+  accountId?: string
+  platform?: string
+  error?: Error
+  metadata?: Record<string, any>
+  correlationId?: string
 }
 
 export interface ErrorContext {
-  component: string;
-  operation: string;
-  accountId?: string;
-  platform?: string;
-  attempt?: number;
-  maxRetries?: number;
-  metadata?: Record<string, any>;
-  correlationId?: string;
+  component: string
+  operation: string
+  accountId?: string
+  platform?: string
+  attempt?: number
+  maxRetries?: number
+  metadata?: Record<string, any>
+  correlationId?: string
 }
 
 export interface RecoveryStrategy {
-  canHandle(error: Error, context: ErrorContext): boolean;
-  handle(error: Error, context: ErrorContext): Promise<RecoveryResult>;
+  canHandle(error: Error, context: ErrorContext): boolean
+  handle(error: Error, context: ErrorContext): Promise<RecoveryResult>
 }
 
 export interface RecoveryResult {
-  recovered: boolean;
-  shouldRetry: boolean;
-  retryDelay?: number;
-  newError?: Error;
-  metadata?: Record<string, any>;
+  recovered: boolean
+  shouldRetry: boolean
+  retryDelay?: number
+  newError?: Error
+  metadata?: Record<string, any>
 }
 
 export enum LogLevel {
@@ -55,25 +56,25 @@ export enum LogLevel {
   INFO = 'info',
   WARN = 'warn',
   ERROR = 'error',
-  FATAL = 'fatal'
+  FATAL = 'fatal',
 }
 
 export enum ErrorSeverity {
   LOW = 'low',
   MEDIUM = 'medium',
   HIGH = 'high',
-  CRITICAL = 'critical'
+  CRITICAL = 'critical',
 }
 
 export interface ErrorHandlerOptions {
-  enableLogging?: boolean;
-  logLevel?: LogLevel;
-  enableConsoleOutput?: boolean;
-  enableErrorRecovery?: boolean;
-  maxRetries?: number;
-  retryDelay?: number;
-  enableAuditTrail?: boolean;
-  enableCorrelationTracking?: boolean;
+  enableLogging?: boolean
+  logLevel?: LogLevel
+  enableConsoleOutput?: boolean
+  enableErrorRecovery?: boolean
+  maxRetries?: number
+  retryDelay?: number
+  enableAuditTrail?: boolean
+  enableCorrelationTracking?: boolean
 }
 
 // ============================================================================
@@ -81,14 +82,14 @@ export interface ErrorHandlerOptions {
 // ============================================================================
 
 export class ErrorHandler extends EventEmitter {
-  private options: Required<ErrorHandlerOptions>;
-  private logEntries: LogEntry[] = [];
-  private errorCounts = new Map<string, number>();
-  private recoveryStrategies: RecoveryStrategy[] = [];
-  private correlationCounter = 0;
+  private options: Required<ErrorHandlerOptions>
+  private logEntries: LogEntry[] = []
+  private errorCounts = new Map<string, number>()
+  private recoveryStrategies: RecoveryStrategy[] = []
+  private correlationCounter = 0
 
   constructor(options: ErrorHandlerOptions = {}) {
-    super();
+    super()
 
     this.options = {
       enableLogging: options.enableLogging ?? true,
@@ -98,34 +99,34 @@ export class ErrorHandler extends EventEmitter {
       maxRetries: options.maxRetries ?? 3,
       retryDelay: options.retryDelay ?? 1000,
       enableAuditTrail: options.enableAuditTrail ?? true,
-      enableCorrelationTracking: options.enableCorrelationTracking ?? true
-    };
+      enableCorrelationTracking: options.enableCorrelationTracking ?? true,
+    }
 
-    this.initializeDefaultRecoveryStrategies();
+    this.initializeDefaultRecoveryStrategies()
   }
 
   /**
    * Handle an error with context and recovery attempts
    */
   async handleError(error: Error, context: ErrorContext): Promise<RecoveryResult> {
-    const correlationId = context.correlationId || this.generateCorrelationId();
-    const enrichedContext = { ...context, correlationId };
+    const correlationId = context.correlationId || this.generateCorrelationId()
+    const enrichedContext = { ...context, correlationId }
 
     // Log the error
-    this.logError(error, enrichedContext);
+    this.logError(error, enrichedContext)
 
     // Track error occurrence
-    this.trackError(error, enrichedContext);
+    this.trackError(error, enrichedContext)
 
     // Attempt recovery if enabled
     if (this.options.enableErrorRecovery) {
-      return await this.attemptRecovery(error, enrichedContext);
+      return await this.attemptRecovery(error, enrichedContext)
     }
 
     return {
       recovered: false,
-      shouldRetry: false
-    };
+      shouldRetry: false,
+    }
   }
 
   /**
@@ -133,7 +134,7 @@ export class ErrorHandler extends EventEmitter {
    */
   log(level: LogLevel, message: string, component: string, metadata?: Record<string, any>): void {
     if (!this.shouldLog(level)) {
-      return;
+      return
     }
 
     const entry: LogEntry = {
@@ -142,31 +143,31 @@ export class ErrorHandler extends EventEmitter {
       message,
       component,
       metadata,
-      correlationId: metadata?.correlationId
-    };
+      correlationId: metadata?.correlationId,
+    }
 
-    this.addLogEntry(entry);
+    this.addLogEntry(entry)
   }
 
   /**
    * Log debug messages
    */
   debug(message: string, component: string, metadata?: Record<string, any>): void {
-    this.log(LogLevel.DEBUG, message, component, metadata);
+    this.log(LogLevel.DEBUG, message, component, metadata)
   }
 
   /**
    * Log info messages
    */
   info(message: string, component: string, metadata?: Record<string, any>): void {
-    this.log(LogLevel.INFO, message, component, metadata);
+    this.log(LogLevel.INFO, message, component, metadata)
   }
 
   /**
    * Log warning messages
    */
   warn(message: string, component: string, metadata?: Record<string, any>): void {
-    this.log(LogLevel.WARN, message, component, metadata);
+    this.log(LogLevel.WARN, message, component, metadata)
   }
 
   /**
@@ -180,10 +181,10 @@ export class ErrorHandler extends EventEmitter {
       component,
       error,
       metadata,
-      correlationId: metadata?.correlationId
-    };
+      correlationId: metadata?.correlationId,
+    }
 
-    this.addLogEntry(entry);
+    this.addLogEntry(entry)
   }
 
   /**
@@ -197,44 +198,42 @@ export class ErrorHandler extends EventEmitter {
       component,
       error,
       metadata,
-      correlationId: metadata?.correlationId
-    };
+      correlationId: metadata?.correlationId,
+    }
 
-    this.addLogEntry(entry);
+    this.addLogEntry(entry)
   }
 
   /**
    * Register a custom recovery strategy
    */
   registerRecoveryStrategy(strategy: RecoveryStrategy): void {
-    this.recoveryStrategies.push(strategy);
+    this.recoveryStrategies.push(strategy)
   }
 
   /**
    * Get error statistics
    */
   getErrorStats(): Record<string, any> {
-    const errorsByType = new Map<string, number>();
-    const errorsByComponent = new Map<string, number>();
-    const recentErrors: LogEntry[] = [];
+    const errorsByType = new Map<string, number>()
+    const errorsByComponent = new Map<string, number>()
+    const recentErrors: LogEntry[] = []
 
     this.logEntries
       .filter(entry => entry.level === LogLevel.ERROR || entry.level === LogLevel.FATAL)
       .forEach(entry => {
         // Count by error type
-        const errorType = entry.error instanceof CredentialManagerError
-          ? entry.error.type
-          : 'unknown';
-        errorsByType.set(errorType, (errorsByType.get(errorType) || 0) + 1);
+        const errorType = entry.error instanceof CredentialManagerError ? entry.error.type : 'unknown'
+        errorsByType.set(errorType, (errorsByType.get(errorType) || 0) + 1)
 
         // Count by component
-        errorsByComponent.set(entry.component, (errorsByComponent.get(entry.component) || 0) + 1);
+        errorsByComponent.set(entry.component, (errorsByComponent.get(entry.component) || 0) + 1)
 
         // Collect recent errors (last 100)
         if (recentErrors.length < 100) {
-          recentErrors.push(entry);
+          recentErrors.push(entry)
         }
-      });
+      })
 
     return {
       totalErrors: this.logEntries.filter(e => e.level === LogLevel.ERROR || e.level === LogLevel.FATAL).length,
@@ -245,9 +244,9 @@ export class ErrorHandler extends EventEmitter {
         component: entry.component,
         message: entry.message,
         errorType: entry.error instanceof CredentialManagerError ? entry.error.type : 'unknown',
-        correlationId: entry.correlationId
-      }))
-    };
+        correlationId: entry.correlationId,
+      })),
+    }
   }
 
   /**
@@ -255,33 +254,33 @@ export class ErrorHandler extends EventEmitter {
    */
   getAuditTrail(filter?: { component?: string; level?: LogLevel; since?: Date }): LogEntry[] {
     if (!this.options.enableAuditTrail) {
-      return [];
+      return []
     }
 
-    let entries = [...this.logEntries];
+    let entries = [...this.logEntries]
 
     if (filter) {
       if (filter.component) {
-        entries = entries.filter(e => e.component === filter.component);
+        entries = entries.filter(e => e.component === filter.component)
       }
       if (filter.level) {
-        entries = entries.filter(e => e.level === filter.level);
+        entries = entries.filter(e => e.level === filter.level)
       }
       if (filter.since) {
-        entries = entries.filter(e => e.timestamp >= filter.since);
+        entries = entries.filter(e => e.timestamp >= filter.since)
       }
     }
 
-    return entries.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
+    return entries.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
   }
 
   /**
    * Clear logs older than specified date
    */
   clearOldLogs(before: Date): number {
-    const initialCount = this.logEntries.length;
-    this.logEntries = this.logEntries.filter(entry => entry.timestamp >= before);
-    return initialCount - this.logEntries.length;
+    const initialCount = this.logEntries.length
+    this.logEntries = this.logEntries.filter(entry => entry.timestamp >= before)
+    return initialCount - this.logEntries.length
   }
 
   /**
@@ -289,11 +288,11 @@ export class ErrorHandler extends EventEmitter {
    */
   generateCorrelationId(): string {
     if (!this.options.enableCorrelationTracking) {
-      return '';
+      return ''
     }
 
-    this.correlationCounter = (this.correlationCounter + 1) % 1000000;
-    return `cm-${Date.now()}-${this.correlationCounter.toString().padStart(6, '0')}`;
+    this.correlationCounter = (this.correlationCounter + 1) % 1000000
+    return `cm-${Date.now()}-${this.correlationCounter.toString().padStart(6, '0')}`
   }
 
   // ============================================================================
@@ -310,9 +309,9 @@ export class ErrorHandler extends EventEmitter {
       handle: async (error: Error, context: ErrorContext) => ({
         recovered: false,
         shouldRetry: (context.attempt || 0) < (context.maxRetries || this.options.maxRetries),
-        retryDelay: this.options.retryDelay * Math.pow(2, context.attempt || 0) // Exponential backoff
-      })
-    });
+        retryDelay: this.options.retryDelay * Math.pow(2, context.attempt || 0), // Exponential backoff
+      }),
+    })
 
     // File not found recovery
     this.registerRecoveryStrategy({
@@ -322,10 +321,10 @@ export class ErrorHandler extends EventEmitter {
         shouldRetry: false,
         newError: new CredentialManagerError(
           `Configuration file not found: ${error.message}`,
-          ErrorType.CONFIG_LOAD_ERROR
-        )
-      })
-    });
+          ErrorType.CONFIG_LOAD_ERROR,
+        ),
+      }),
+    })
 
     // Validation error recovery
     this.registerRecoveryStrategy({
@@ -333,42 +332,43 @@ export class ErrorHandler extends EventEmitter {
       handle: async (error: Error, context: ErrorContext) => ({
         recovered: false,
         shouldRetry: false,
-        newError: error // Don't retry validation errors
-      })
-    });
+        newError: error, // Don't retry validation errors
+      }),
+    })
 
     // Generic retry strategy for temporary failures
     this.registerRecoveryStrategy({
-      canHandle: (error: Error) => error instanceof CredentialManagerError &&
+      canHandle: (error: Error) =>
+        error instanceof CredentialManagerError &&
         [ErrorType.SIGNATURE_ERROR, ErrorType.CONFIG_LOAD_ERROR].includes(error.type),
       handle: async (error: Error, context: ErrorContext) => {
-        const attempt = context.attempt || 0;
-        const maxRetries = context.maxRetries || this.options.maxRetries;
+        const attempt = context.attempt || 0
+        const maxRetries = context.maxRetries || this.options.maxRetries
 
         return {
           recovered: false,
           shouldRetry: attempt < maxRetries,
-          retryDelay: this.options.retryDelay * (attempt + 1)
-        };
-      }
-    });
+          retryDelay: this.options.retryDelay * (attempt + 1),
+        }
+      },
+    })
   }
 
   /**
    * Log an error with context
    */
   private logError(error: Error, context: ErrorContext): void {
-    const severity = this.determineErrorSeverity(error);
-    const level = severity === ErrorSeverity.CRITICAL ? LogLevel.FATAL : LogLevel.ERROR;
+    const severity = this.determineErrorSeverity(error)
+    const level = severity === ErrorSeverity.CRITICAL ? LogLevel.FATAL : LogLevel.ERROR
 
-    const message = `${context.operation} failed: ${error.message}`;
+    const message = `${context.operation} failed: ${error.message}`
 
     const metadata = {
       ...context.metadata,
       severity,
       errorType: error instanceof CredentialManagerError ? error.type : 'unknown',
-      correlationId: context.correlationId
-    };
+      correlationId: context.correlationId,
+    }
 
     const entry: LogEntry = {
       timestamp: new Date(),
@@ -380,26 +380,26 @@ export class ErrorHandler extends EventEmitter {
       platform: context.platform,
       error,
       metadata,
-      correlationId: context.correlationId
-    };
+      correlationId: context.correlationId,
+    }
 
-    this.addLogEntry(entry);
+    this.addLogEntry(entry)
   }
 
   /**
    * Track error occurrences for monitoring
    */
   private trackError(error: Error, context: ErrorContext): void {
-    const errorKey = `${context.component}:${error.constructor.name}`;
-    const count = this.errorCounts.get(errorKey) || 0;
-    this.errorCounts.set(errorKey, count + 1);
+    const errorKey = `${context.component}:${error.constructor.name}`
+    const count = this.errorCounts.get(errorKey) || 0
+    this.errorCounts.set(errorKey, count + 1)
 
     // Emit error event for external monitoring
     this.emit('error', {
       error,
       context,
-      count: count + 1
-    });
+      count: count + 1,
+    })
   }
 
   /**
@@ -409,22 +409,22 @@ export class ErrorHandler extends EventEmitter {
     for (const strategy of this.recoveryStrategies) {
       if (strategy.canHandle(error, context)) {
         try {
-          const result = await strategy.handle(error, context);
+          const result = await strategy.handle(error, context)
 
           this.debug(`Recovery strategy applied`, 'ErrorHandler', {
             strategy: strategy.constructor.name,
             recovered: result.recovered,
             shouldRetry: result.shouldRetry,
-            correlationId: context.correlationId
-          });
+            correlationId: context.correlationId,
+          })
 
-          return result;
+          return result
         } catch (recoveryError) {
           this.warn(`Recovery strategy failed`, 'ErrorHandler', {
             strategy: strategy.constructor.name,
             error: recoveryError.message,
-            correlationId: context.correlationId
-          });
+            correlationId: context.correlationId,
+          })
         }
       }
     }
@@ -432,8 +432,8 @@ export class ErrorHandler extends EventEmitter {
     // No strategy could handle the error
     return {
       recovered: false,
-      shouldRetry: false
-    };
+      shouldRetry: false,
+    }
   }
 
   /**
@@ -443,24 +443,24 @@ export class ErrorHandler extends EventEmitter {
     if (error instanceof CredentialManagerError) {
       switch (error.type) {
         case ErrorType.VALIDATION_ERROR:
-          return ErrorSeverity.MEDIUM;
+          return ErrorSeverity.MEDIUM
         case ErrorType.CONFIG_LOAD_ERROR:
-          return ErrorSeverity.HIGH;
+          return ErrorSeverity.HIGH
         case ErrorType.SIGNATURE_ERROR:
-          return ErrorSeverity.HIGH;
+          return ErrorSeverity.HIGH
         case ErrorType.PLATFORM_DETECTION_ERROR:
-          return ErrorSeverity.MEDIUM;
+          return ErrorSeverity.MEDIUM
         default:
-          return ErrorSeverity.MEDIUM;
+          return ErrorSeverity.MEDIUM
       }
     }
 
     // Check for critical system errors
     if (error.message.includes('EMFILE') || error.message.includes('ENOMEM')) {
-      return ErrorSeverity.CRITICAL;
+      return ErrorSeverity.CRITICAL
     }
 
-    return ErrorSeverity.LOW;
+    return ErrorSeverity.LOW
   }
 
   /**
@@ -468,14 +468,14 @@ export class ErrorHandler extends EventEmitter {
    */
   private shouldLog(level: LogLevel): boolean {
     if (!this.options.enableLogging) {
-      return false;
+      return false
     }
 
-    const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
-    const currentLevelIndex = levels.indexOf(this.options.logLevel);
-    const messageLevelIndex = levels.indexOf(level);
+    const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL]
+    const currentLevelIndex = levels.indexOf(this.options.logLevel)
+    const messageLevelIndex = levels.indexOf(level)
 
-    return messageLevelIndex >= currentLevelIndex;
+    return messageLevelIndex >= currentLevelIndex
   }
 
   /**
@@ -483,70 +483,70 @@ export class ErrorHandler extends EventEmitter {
    */
   private addLogEntry(entry: LogEntry): void {
     if (this.options.enableAuditTrail) {
-      this.logEntries.push(entry);
+      this.logEntries.push(entry)
 
       // Keep only recent entries to prevent memory leaks
       if (this.logEntries.length > 10000) {
-        this.logEntries = this.logEntries.slice(-5000);
+        this.logEntries = this.logEntries.slice(-5000)
       }
     }
 
     if (this.options.enableConsoleOutput) {
-      this.outputToConsole(entry);
+      this.outputToConsole(entry)
     }
 
     // Emit log event for external listeners
-    this.emit('log', entry);
+    this.emit('log', entry)
   }
 
   /**
    * Output log entry to console with appropriate formatting
    */
   private outputToConsole(entry: LogEntry): void {
-    const timestamp = entry.timestamp.toISOString();
-    const level = entry.level.toUpperCase().padEnd(5);
-    const component = entry.component.padEnd(20);
+    const timestamp = entry.timestamp.toISOString()
+    const level = entry.level.toUpperCase().padEnd(5)
+    const component = entry.component.padEnd(20)
 
-    let message = `[${timestamp}] ${level} ${component} ${entry.message}`;
+    let message = `[${timestamp}] ${level} ${component} ${entry.message}`
 
     if (entry.correlationId) {
-      message += ` [${entry.correlationId}]`;
+      message += ` [${entry.correlationId}]`
     }
 
     if (entry.accountId) {
-      message += ` (account: ${entry.accountId})`;
+      message += ` (account: ${entry.accountId})`
     }
 
     if (entry.platform) {
-      message += ` (platform: ${entry.platform})`;
+      message += ` (platform: ${entry.platform})`
     }
 
     switch (entry.level) {
       case LogLevel.DEBUG:
-        console.debug(message);
-        break;
+        console.debug(message)
+        break
       case LogLevel.INFO:
-        console.info(message);
-        break;
+        console.info(message)
+        break
       case LogLevel.WARN:
-        console.warn(message);
-        break;
+        console.warn(message)
+        break
       case LogLevel.ERROR:
-        console.error(message);
+        console.error(message)
         if (entry.error) {
-          console.error(entry.error.stack);
+          console.error(entry.error.stack)
         }
-        break;
+        break
       case LogLevel.FATAL:
-        console.error(message);
+        console.error(message)
         if (entry.error) {
-          console.error(entry.error.stack);
+          console.error(entry.error.stack)
         }
-        break;
+        break
     }
 
     if (entry.metadata && Object.keys(entry.metadata).length > 0) {
-      console.debug('Metadata:', entry.metadata);
+      console.debug('Metadata:', entry.metadata)
     }
   }
 }
@@ -559,7 +559,7 @@ export class ErrorHandler extends EventEmitter {
  * Create error handler with default options
  */
 export function createErrorHandler(options?: ErrorHandlerOptions): ErrorHandler {
-  return new ErrorHandler(options);
+  return new ErrorHandler(options)
 }
 
 /**
@@ -574,8 +574,8 @@ export function createProductionErrorHandler(): ErrorHandler {
     maxRetries: 3,
     retryDelay: 1000,
     enableAuditTrail: true,
-    enableCorrelationTracking: true
-  });
+    enableCorrelationTracking: true,
+  })
 }
 
 /**
@@ -590,34 +590,34 @@ export function createDevelopmentErrorHandler(): ErrorHandler {
     maxRetries: 5,
     retryDelay: 500,
     enableAuditTrail: true,
-    enableCorrelationTracking: true
-  });
+    enableCorrelationTracking: true,
+  })
 }
 
 /**
  * Global error handler instance for convenience
  */
-let globalErrorHandler: ErrorHandler | null = null;
+let globalErrorHandler: ErrorHandler | null = null
 
 /**
  * Get or create global error handler instance
  */
 export function getGlobalErrorHandler(): ErrorHandler {
   if (!globalErrorHandler) {
-    globalErrorHandler = createErrorHandler();
+    globalErrorHandler = createErrorHandler()
   }
-  return globalErrorHandler;
+  return globalErrorHandler
 }
 
 /**
  * Set global error handler instance
  */
 export function setGlobalErrorHandler(handler: ErrorHandler): void {
-  globalErrorHandler = handler;
+  globalErrorHandler = handler
 }
 
 // ============================================================================
 // Export
 // ============================================================================
 
-export default ErrorHandler;
+export default ErrorHandler

+ 146 - 164
src/core/credential-manager/FileWatcher.ts

@@ -6,14 +6,15 @@
  * Uses Node.js fs.watch for efficient file system monitoring.
  */
 
-import { watch, FSWatcher, stat, access, constants } from 'fs';
-import { promisify } from 'util';
-import { EventEmitter } from 'events';
-import { CredentialManagerError, ErrorType } from '../../types/credential.js';
+import { EventEmitter } from 'events'
+import { watch, FSWatcher, stat, access, constants } from 'fs'
+import { promisify } from 'util'
+
+import { CredentialManagerError, ErrorType } from '../../types/credential.js'
 
 // Promisify fs functions
-const statAsync = promisify(stat);
-const accessAsync = promisify(access);
+const statAsync = promisify(stat)
+const accessAsync = promisify(access)
 
 // ============================================================================
 // Types and Interfaces
@@ -24,50 +25,50 @@ export interface FileWatcherOptions {
    * Debounce delay in milliseconds
    * @default 100
    */
-  debounceDelay?: number;
+  debounceDelay?: number
 
   /**
    * Whether to watch for file creation if file doesn't exist
    * @default true
    */
-  watchForCreation?: boolean;
+  watchForCreation?: boolean
 
   /**
    * Whether to emit events for file deletion
    * @default true
    */
-  watchForDeletion?: boolean;
+  watchForDeletion?: boolean
 
   /**
    * Maximum number of retries for failed watch operations
    * @default 3
    */
-  maxRetries?: number;
+  maxRetries?: number
 
   /**
    * Delay between retry attempts in milliseconds
    * @default 1000
    */
-  retryDelay?: number;
+  retryDelay?: number
 
   /**
    * Whether to enable detailed logging
    * @default false
    */
-  enableLogging?: boolean;
+  enableLogging?: boolean
 }
 
 export interface FileChangeEvent {
-  path: string;
-  type: 'change' | 'create' | 'delete' | 'error';
-  timestamp: Date;
-  error?: Error;
+  path: string
+  type: 'change' | 'create' | 'delete' | 'error'
+  timestamp: Date
+  error?: Error
 }
 
 export interface FileStats {
-  size: number;
-  mtime: Date;
-  exists: boolean;
+  size: number
+  mtime: Date
+  exists: boolean
 }
 
 // ============================================================================
@@ -75,14 +76,14 @@ export interface FileStats {
 // ============================================================================
 
 export class FileWatcher extends EventEmitter {
-  private watchers = new Map<string, FSWatcher>();
-  private debounceTimers = new Map<string, NodeJS.Timeout>();
-  private fileStats = new Map<string, FileStats>();
-  private options: Required<FileWatcherOptions>;
-  private retryCounters = new Map<string, number>();
+  private watchers = new Map<string, FSWatcher>()
+  private debounceTimers = new Map<string, NodeJS.Timeout>()
+  private fileStats = new Map<string, FileStats>()
+  private options: Required<FileWatcherOptions>
+  private retryCounters = new Map<string, number>()
 
   constructor(options: FileWatcherOptions = {}) {
-    super();
+    super()
 
     this.options = {
       debounceDelay: options.debounceDelay ?? 100,
@@ -90,57 +91,53 @@ export class FileWatcher extends EventEmitter {
       watchForDeletion: options.watchForDeletion ?? true,
       maxRetries: options.maxRetries ?? 3,
       retryDelay: options.retryDelay ?? 1000,
-      enableLogging: options.enableLogging ?? false
-    };
+      enableLogging: options.enableLogging ?? false,
+    }
   }
 
   /**
    * Start watching a file for changes
    */
-  async watchFile(
-    filePath: string,
-    callback?: (event: FileChangeEvent) => void
-  ): Promise<void> {
+  async watchFile(filePath: string, callback?: (event: FileChangeEvent) => void): Promise<void> {
     try {
       // Check if already watching this file
       if (this.watchers.has(filePath)) {
-        this.log(`Already watching file: ${filePath}`);
-        return;
+        this.log(`Already watching file: ${filePath}`)
+        return
       }
 
       // Initialize file stats
-      await this.updateFileStats(filePath);
+      await this.updateFileStats(filePath)
 
       // Create debounced change handler
-      const debouncedHandler = this.createDebouncedHandler(filePath, callback);
+      const debouncedHandler = this.createDebouncedHandler(filePath, callback)
 
       // Set up file watcher
       const watcher = watch(filePath, { persistent: true }, (eventType, filename) => {
-        this.log(`File system event: ${eventType} for ${filename || filePath}`);
-        debouncedHandler(eventType);
-      });
+        this.log(`File system event: ${eventType} for ${filename || filePath}`)
+        debouncedHandler(eventType)
+      })
 
       // Handle watcher errors
-      watcher.on('error', (error) => {
-        this.handleWatcherError(filePath, error, callback);
-      });
+      watcher.on('error', error => {
+        this.handleWatcherError(filePath, error, callback)
+      })
 
-      this.watchers.set(filePath, watcher);
-      this.retryCounters.set(filePath, 0);
+      this.watchers.set(filePath, watcher)
+      this.retryCounters.set(filePath, 0)
 
-      this.log(`Started watching file: ${filePath}`);
+      this.log(`Started watching file: ${filePath}`)
 
       // Emit initial event if callback provided
       if (callback) {
         callback({
           path: filePath,
           type: 'create',
-          timestamp: new Date()
-        });
+          timestamp: new Date(),
+        })
       }
-
     } catch (error) {
-      this.handleWatchError(filePath, error, callback);
+      this.handleWatchError(filePath, error, callback)
     }
   }
 
@@ -148,32 +145,31 @@ export class FileWatcher extends EventEmitter {
    * Stop watching a specific file
    */
   stopWatchingFile(filePath: string): boolean {
-    const watcher = this.watchers.get(filePath);
+    const watcher = this.watchers.get(filePath)
     if (!watcher) {
-      return false;
+      return false
     }
 
     try {
-      watcher.close();
-      this.watchers.delete(filePath);
+      watcher.close()
+      this.watchers.delete(filePath)
 
       // Clear debounce timer
-      const timer = this.debounceTimers.get(filePath);
+      const timer = this.debounceTimers.get(filePath)
       if (timer) {
-        clearTimeout(timer);
-        this.debounceTimers.delete(filePath);
+        clearTimeout(timer)
+        this.debounceTimers.delete(filePath)
       }
 
       // Clean up stats and retry counters
-      this.fileStats.delete(filePath);
-      this.retryCounters.delete(filePath);
-
-      this.log(`Stopped watching file: ${filePath}`);
-      return true;
+      this.fileStats.delete(filePath)
+      this.retryCounters.delete(filePath)
 
+      this.log(`Stopped watching file: ${filePath}`)
+      return true
     } catch (error) {
-      this.log(`Error stopping file watcher for ${filePath}: ${error.message}`);
-      return false;
+      this.log(`Error stopping file watcher for ${filePath}: ${error.message}`)
+      return false
     }
   }
 
@@ -181,27 +177,27 @@ export class FileWatcher extends EventEmitter {
    * Stop watching all files
    */
   stopWatchingAll(): void {
-    const watchedFiles = Array.from(this.watchers.keys());
+    const watchedFiles = Array.from(this.watchers.keys())
 
     for (const filePath of watchedFiles) {
-      this.stopWatchingFile(filePath);
+      this.stopWatchingFile(filePath)
     }
 
-    this.log('Stopped watching all files');
+    this.log('Stopped watching all files')
   }
 
   /**
    * Get list of currently watched files
    */
   getWatchedFiles(): string[] {
-    return Array.from(this.watchers.keys());
+    return Array.from(this.watchers.keys())
   }
 
   /**
    * Check if a file is currently being watched
    */
   isWatching(filePath: string): boolean {
-    return this.watchers.has(filePath);
+    return this.watchers.has(filePath)
   }
 
   /**
@@ -209,10 +205,10 @@ export class FileWatcher extends EventEmitter {
    */
   async getFileStats(filePath: string): Promise<FileStats | null> {
     try {
-      await this.updateFileStats(filePath);
-      return this.fileStats.get(filePath) || null;
+      await this.updateFileStats(filePath)
+      return this.fileStats.get(filePath) || null
     } catch (error) {
-      return null;
+      return null
     }
   }
 
@@ -221,21 +217,19 @@ export class FileWatcher extends EventEmitter {
    */
   async checkForChanges(filePath: string): Promise<boolean> {
     try {
-      const oldStats = this.fileStats.get(filePath);
-      await this.updateFileStats(filePath);
-      const newStats = this.fileStats.get(filePath);
+      const oldStats = this.fileStats.get(filePath)
+      await this.updateFileStats(filePath)
+      const newStats = this.fileStats.get(filePath)
 
       if (!oldStats || !newStats) {
-        return false;
+        return false
       }
 
       // Check if file has been modified
-      return newStats.mtime.getTime() !== oldStats.mtime.getTime() ||
-             newStats.size !== oldStats.size;
-
+      return newStats.mtime.getTime() !== oldStats.mtime.getTime() || newStats.size !== oldStats.size
     } catch (error) {
-      this.log(`Error checking file changes for ${filePath}: ${error.message}`);
-      return false;
+      this.log(`Error checking file changes for ${filePath}: ${error.message}`)
+      return false
     }
   }
 
@@ -248,28 +242,28 @@ export class FileWatcher extends EventEmitter {
    */
   private createDebouncedHandler(
     filePath: string,
-    callback?: (event: FileChangeEvent) => void
+    callback?: (event: FileChangeEvent) => void,
   ): (eventType: string) => void {
     return (eventType: string) => {
       // Clear existing timer
-      const existingTimer = this.debounceTimers.get(filePath);
+      const existingTimer = this.debounceTimers.get(filePath)
       if (existingTimer) {
-        clearTimeout(existingTimer);
+        clearTimeout(existingTimer)
       }
 
       // Set new debounced timer
       const timer = setTimeout(async () => {
         try {
-          await this.handleFileChange(filePath, eventType, callback);
+          await this.handleFileChange(filePath, eventType, callback)
         } catch (error) {
-          this.handleWatchError(filePath, error, callback);
+          this.handleWatchError(filePath, error, callback)
         } finally {
-          this.debounceTimers.delete(filePath);
+          this.debounceTimers.delete(filePath)
         }
-      }, this.options.debounceDelay);
+      }, this.options.debounceDelay)
 
-      this.debounceTimers.set(filePath, timer);
-    };
+      this.debounceTimers.set(filePath, timer)
+    }
   }
 
   /**
@@ -278,147 +272,135 @@ export class FileWatcher extends EventEmitter {
   private async handleFileChange(
     filePath: string,
     eventType: string,
-    callback?: (event: FileChangeEvent) => void
+    callback?: (event: FileChangeEvent) => void,
   ): Promise<void> {
     try {
-      const oldStats = this.fileStats.get(filePath);
-      const currentlyExists = await this.fileExists(filePath);
+      const oldStats = this.fileStats.get(filePath)
+      const currentlyExists = await this.fileExists(filePath)
 
-      let changeType: 'change' | 'create' | 'delete';
+      let changeType: 'change' | 'create' | 'delete'
 
       if (!oldStats?.exists && currentlyExists) {
         // File was created
-        changeType = 'create';
+        changeType = 'create'
         if (!this.options.watchForCreation) {
-          return;
+          return
         }
       } else if (oldStats?.exists && !currentlyExists) {
         // File was deleted
-        changeType = 'delete';
+        changeType = 'delete'
         if (!this.options.watchForDeletion) {
-          return;
+          return
         }
       } else if (currentlyExists) {
         // File was modified
-        changeType = 'change';
+        changeType = 'change'
 
         // Check if file actually changed
-        const hasChanged = await this.checkForChanges(filePath);
+        const hasChanged = await this.checkForChanges(filePath)
         if (!hasChanged) {
-          this.log(`File ${filePath} event fired but no actual changes detected`);
-          return;
+          this.log(`File ${filePath} event fired but no actual changes detected`)
+          return
         }
       } else {
         // No significant change
-        return;
+        return
       }
 
       // Update file stats
       if (currentlyExists) {
-        await this.updateFileStats(filePath);
+        await this.updateFileStats(filePath)
       } else {
         this.fileStats.set(filePath, {
           size: 0,
           mtime: new Date(),
-          exists: false
-        });
+          exists: false,
+        })
       }
 
       // Reset retry counter on successful operation
-      this.retryCounters.set(filePath, 0);
+      this.retryCounters.set(filePath, 0)
 
       const event: FileChangeEvent = {
         path: filePath,
         type: changeType,
-        timestamp: new Date()
-      };
+        timestamp: new Date(),
+      }
 
-      this.log(`File ${changeType}: ${filePath}`);
+      this.log(`File ${changeType}: ${filePath}`)
 
       // Emit event
-      this.emit('change', event);
+      this.emit('change', event)
 
       // Call callback if provided
       if (callback) {
-        callback(event);
+        callback(event)
       }
-
     } catch (error) {
-      this.handleWatchError(filePath, error, callback);
+      this.handleWatchError(filePath, error, callback)
     }
   }
 
   /**
    * Handle watcher errors with retry logic
    */
-  private handleWatcherError(
-    filePath: string,
-    error: Error,
-    callback?: (event: FileChangeEvent) => void
-  ): void {
-    this.log(`Watcher error for ${filePath}: ${error.message}`);
+  private handleWatcherError(filePath: string, error: Error, callback?: (event: FileChangeEvent) => void): void {
+    this.log(`Watcher error for ${filePath}: ${error.message}`)
 
-    const retryCount = this.retryCounters.get(filePath) || 0;
+    const retryCount = this.retryCounters.get(filePath) || 0
 
     if (retryCount < this.options.maxRetries) {
-      this.log(`Retrying watch setup for ${filePath} (attempt ${retryCount + 1})`);
-      this.retryCounters.set(filePath, retryCount + 1);
+      this.log(`Retrying watch setup for ${filePath} (attempt ${retryCount + 1})`)
+      this.retryCounters.set(filePath, retryCount + 1)
 
       setTimeout(() => {
-        this.restartWatcher(filePath, callback);
-      }, this.options.retryDelay);
+        this.restartWatcher(filePath, callback)
+      }, this.options.retryDelay)
     } else {
-      this.log(`Max retries exceeded for ${filePath}, stopping watcher`);
-      this.stopWatchingFile(filePath);
-      this.handleWatchError(filePath, error, callback);
+      this.log(`Max retries exceeded for ${filePath}, stopping watcher`)
+      this.stopWatchingFile(filePath)
+      this.handleWatchError(filePath, error, callback)
     }
   }
 
   /**
    * Handle general watch errors
    */
-  private handleWatchError(
-    filePath: string,
-    error: any,
-    callback?: (event: FileChangeEvent) => void
-  ): void {
+  private handleWatchError(filePath: string, error: any, callback?: (event: FileChangeEvent) => void): void {
     const watchError = new CredentialManagerError(
       `File watch error for ${filePath}: ${error.message}`,
-      ErrorType.CONFIG_LOAD_ERROR
-    );
+      ErrorType.CONFIG_LOAD_ERROR,
+    )
 
     const event: FileChangeEvent = {
       path: filePath,
       type: 'error',
       timestamp: new Date(),
-      error: watchError
-    };
+      error: watchError,
+    }
 
-    this.emit('error', event);
+    this.emit('error', event)
 
     if (callback) {
-      callback(event);
+      callback(event)
     }
   }
 
   /**
    * Restart a watcher after error
    */
-  private async restartWatcher(
-    filePath: string,
-    callback?: (event: FileChangeEvent) => void
-  ): Promise<void> {
+  private async restartWatcher(filePath: string, callback?: (event: FileChangeEvent) => void): Promise<void> {
     // Stop existing watcher
-    this.stopWatchingFile(filePath);
+    this.stopWatchingFile(filePath)
 
     // Wait a bit before restarting
-    await new Promise(resolve => setTimeout(resolve, 100));
+    await new Promise(resolve => setTimeout(resolve, 100))
 
     // Restart watching
     try {
-      await this.watchFile(filePath, callback);
+      await this.watchFile(filePath, callback)
     } catch (error) {
-      this.handleWatchError(filePath, error, callback);
+      this.handleWatchError(filePath, error, callback)
     }
   }
 
@@ -427,19 +409,19 @@ export class FileWatcher extends EventEmitter {
    */
   private async updateFileStats(filePath: string): Promise<void> {
     try {
-      const stats = await statAsync(filePath);
+      const stats = await statAsync(filePath)
       this.fileStats.set(filePath, {
         size: stats.size,
         mtime: stats.mtime,
-        exists: true
-      });
+        exists: true,
+      })
     } catch (error) {
       // File doesn't exist or is inaccessible
       this.fileStats.set(filePath, {
         size: 0,
         mtime: new Date(),
-        exists: false
-      });
+        exists: false,
+      })
     }
   }
 
@@ -448,10 +430,10 @@ export class FileWatcher extends EventEmitter {
    */
   private async fileExists(filePath: string): Promise<boolean> {
     try {
-      await accessAsync(filePath, constants.F_OK);
-      return true;
+      await accessAsync(filePath, constants.F_OK)
+      return true
     } catch (error) {
-      return false;
+      return false
     }
   }
 
@@ -460,7 +442,7 @@ export class FileWatcher extends EventEmitter {
    */
   private log(message: string): void {
     if (this.options.enableLogging) {
-      console.log(`[FileWatcher] ${message}`);
+      console.log(`[FileWatcher] ${message}`)
     }
   }
 }
@@ -473,7 +455,7 @@ export class FileWatcher extends EventEmitter {
  * Create a file watcher with default options
  */
 export function createFileWatcher(options?: FileWatcherOptions): FileWatcher {
-  return new FileWatcher(options);
+  return new FileWatcher(options)
 }
 
 /**
@@ -486,8 +468,8 @@ export function createConfigFileWatcher(): FileWatcher {
     watchForDeletion: true,
     maxRetries: 5,
     retryDelay: 1000,
-    enableLogging: false
-  });
+    enableLogging: false,
+  })
 }
 
 /**
@@ -500,8 +482,8 @@ export function createDevFileWatcher(): FileWatcher {
     watchForDeletion: true,
     maxRetries: 3,
     retryDelay: 500,
-    enableLogging: true
-  });
+    enableLogging: true,
+  })
 }
 
 /**
@@ -510,15 +492,15 @@ export function createDevFileWatcher(): FileWatcher {
 export async function watchSingleFile(
   filePath: string,
   callback: (event: FileChangeEvent) => void,
-  options?: FileWatcherOptions
+  options?: FileWatcherOptions,
 ): Promise<FileWatcher> {
-  const watcher = new FileWatcher(options);
-  await watcher.watchFile(filePath, callback);
-  return watcher;
+  const watcher = new FileWatcher(options)
+  await watcher.watchFile(filePath, callback)
+  return watcher
 }
 
 // ============================================================================
 // Export
 // ============================================================================
 
-export default FileWatcher;
+export default FileWatcher

+ 86 - 88
src/core/credential-manager/PlatformDetector.ts

@@ -5,46 +5,46 @@
  * key formats, and other distinguishing characteristics.
  */
 
-import { Platform, IPlatformDetector, Credentials } from '@/types/credential';
+import { Platform, IPlatformDetector, Credentials } from '@/types/credential'
 
 /**
  * Pacifica platform detector
  * Detects Ed25519 credentials with specific patterns
  */
 export class PacificaDetector implements IPlatformDetector {
-  readonly confidence = 0.9;
+  readonly confidence = 0.9
 
   detect(credentials: any): Platform | null {
     if (!credentials || typeof credentials !== 'object') {
-      return null;
+      return null
     }
 
     // Check for Ed25519 signature type
     if (credentials.type === 'ed25519') {
-      return Platform.PACIFICA;
+      return Platform.PACIFICA
     }
 
     // Check for 64-character hex private key (Ed25519 format)
     if (credentials.privateKey && typeof credentials.privateKey === 'string') {
-      const privateKey = credentials.privateKey.toLowerCase();
+      const privateKey = credentials.privateKey.toLowerCase()
 
       // Ed25519 private key: 64 hex characters (32 bytes)
       if (/^[0-9a-f]{64}$/.test(privateKey)) {
-        return Platform.PACIFICA;
+        return Platform.PACIFICA
       }
     }
 
     // Check for base58 public key pattern (common in Pacifica)
     if (credentials.publicKey && typeof credentials.publicKey === 'string') {
-      const publicKey = credentials.publicKey;
+      const publicKey = credentials.publicKey
 
       // Base58 encoded keys are typically 32-44 characters
       if (/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(publicKey) && !publicKey.startsWith('0x')) {
-        return Platform.PACIFICA;
+        return Platform.PACIFICA
       }
     }
 
-    return null;
+    return null
   }
 }
 
@@ -53,49 +53,49 @@ export class PacificaDetector implements IPlatformDetector {
  * Detects EIP-191 (Ethereum-style) credentials
  */
 export class AsterDetector implements IPlatformDetector {
-  readonly confidence = 0.85;
+  readonly confidence = 0.85
 
   detect(credentials: any): Platform | null {
     if (!credentials || typeof credentials !== 'object') {
-      return null;
+      return null
     }
 
     // Check for EIP-191 signature type
     if (credentials.type === 'eip191') {
-      return Platform.ASTER;
+      return Platform.ASTER
     }
 
     // Check for 0x-prefixed private key (Ethereum format)
     if (credentials.privateKey && typeof credentials.privateKey === 'string') {
-      const privateKey = credentials.privateKey.toLowerCase();
+      const privateKey = credentials.privateKey.toLowerCase()
 
       // Ethereum private key: 0x + 64 hex characters
       if (/^0x[0-9a-f]{64}$/.test(privateKey)) {
-        return Platform.ASTER;
+        return Platform.ASTER
       }
     }
 
     // Check for Ethereum address pattern
     if (credentials.address && typeof credentials.address === 'string') {
-      const address = credentials.address.toLowerCase();
+      const address = credentials.address.toLowerCase()
 
       // Ethereum address: 0x + 40 hex characters
       if (/^0x[0-9a-f]{40}$/.test(address)) {
-        return Platform.ASTER;
+        return Platform.ASTER
       }
     }
 
     // Check for public key in Ethereum format
     if (credentials.publicKey && typeof credentials.publicKey === 'string') {
-      const publicKey = credentials.publicKey.toLowerCase();
+      const publicKey = credentials.publicKey.toLowerCase()
 
       // Ethereum public key: 0x + 128 hex characters (uncompressed)
       if (/^0x[0-9a-f]{128}$/.test(publicKey)) {
-        return Platform.ASTER;
+        return Platform.ASTER
       }
     }
 
-    return null;
+    return null
   }
 }
 
@@ -104,43 +104,43 @@ export class AsterDetector implements IPlatformDetector {
  * Detects HMAC-SHA256 API key/secret credentials
  */
 export class BinanceDetector implements IPlatformDetector {
-  readonly confidence = 0.95;
+  readonly confidence = 0.95
 
   detect(credentials: any): Platform | null {
     if (!credentials || typeof credentials !== 'object') {
-      return null;
+      return null
     }
 
     // Check for HMAC signature type
     if (credentials.type === 'hmac') {
-      return Platform.BINANCE;
+      return Platform.BINANCE
     }
 
     // Check for API key/secret pattern
-    const hasApiKey = credentials.apiKey && typeof credentials.apiKey === 'string';
-    const hasSecretKey = credentials.secretKey && typeof credentials.secretKey === 'string';
+    const hasApiKey = credentials.apiKey && typeof credentials.apiKey === 'string'
+    const hasSecretKey = credentials.secretKey && typeof credentials.secretKey === 'string'
 
     if (hasApiKey && hasSecretKey) {
-      const apiKey = credentials.apiKey;
-      const secretKey = credentials.secretKey;
+      const apiKey = credentials.apiKey
+      const secretKey = credentials.secretKey
 
       // Binance API keys are typically 64 characters, alphanumeric
-      const binanceApiKeyPattern = /^[A-Za-z0-9]{64}$/;
+      const binanceApiKeyPattern = /^[A-Za-z0-9]{64}$/
 
       // Binance secret keys are typically 64 characters, alphanumeric
-      const binanceSecretKeyPattern = /^[A-Za-z0-9]{64}$/;
+      const binanceSecretKeyPattern = /^[A-Za-z0-9]{64}$/
 
       if (binanceApiKeyPattern.test(apiKey) && binanceSecretKeyPattern.test(secretKey)) {
-        return Platform.BINANCE;
+        return Platform.BINANCE
       }
 
       // Alternative: any API key/secret combination for HMAC
       if (apiKey.length >= 16 && secretKey.length >= 16) {
-        return Platform.BINANCE;
+        return Platform.BINANCE
       }
     }
 
-    return null;
+    return null
   }
 }
 
@@ -148,14 +148,14 @@ export class BinanceDetector implements IPlatformDetector {
  * Main platform detector that uses multiple detectors
  */
 export class PlatformDetector {
-  private detectors: IPlatformDetector[];
+  private detectors: IPlatformDetector[]
 
   constructor() {
     this.detectors = [
-      new BinanceDetector(),  // Highest confidence first
+      new BinanceDetector(), // Highest confidence first
       new PacificaDetector(),
-      new AsterDetector()
-    ];
+      new AsterDetector(),
+    ]
   }
 
   /**
@@ -165,18 +165,18 @@ export class PlatformDetector {
    */
   detectPlatform(credentials: any): Platform | null {
     if (!credentials) {
-      return null;
+      return null
     }
 
     // Try each detector in order of confidence
     for (const detector of this.detectors) {
-      const platform = detector.detect(credentials);
+      const platform = detector.detect(credentials)
       if (platform) {
-        return platform;
+        return platform
       }
     }
 
-    return null;
+    return null
   }
 
   /**
@@ -185,22 +185,22 @@ export class PlatformDetector {
    * @returns Array of detection results with confidence scores
    */
   getAllDetectionResults(credentials: any): Array<{
-    platform: Platform | null;
-    confidence: number;
-    detector: string;
+    platform: Platform | null
+    confidence: number
+    detector: string
   }> {
-    const results = [];
+    const results = []
 
     for (const detector of this.detectors) {
-      const platform = detector.detect(credentials);
+      const platform = detector.detect(credentials)
       results.push({
         platform,
         confidence: detector.confidence,
-        detector: detector.constructor.name
-      });
+        detector: detector.constructor.name,
+      })
     }
 
-    return results;
+    return results
   }
 
   /**
@@ -210,8 +210,8 @@ export class PlatformDetector {
    * @returns True if credentials match the platform
    */
   validatePlatformMatch(credentials: any, expectedPlatform: Platform): boolean {
-    const detectedPlatform = this.detectPlatform(credentials);
-    return detectedPlatform === expectedPlatform;
+    const detectedPlatform = this.detectPlatform(credentials)
+    return detectedPlatform === expectedPlatform
   }
 
   /**
@@ -220,26 +220,26 @@ export class PlatformDetector {
    * @returns Array of possible platforms with confidence scores
    */
   getSuggestedPlatforms(credentials: any): Array<{
-    platform: Platform;
-    confidence: number;
-    reason: string;
+    platform: Platform
+    confidence: number
+    reason: string
   }> {
-    const suggestions = [];
+    const suggestions = []
 
-    const results = this.getAllDetectionResults(credentials);
+    const results = this.getAllDetectionResults(credentials)
 
     for (const result of results) {
       if (result.platform) {
         suggestions.push({
           platform: result.platform,
           confidence: result.confidence,
-          reason: `Detected by ${result.detector}`
-        });
+          reason: `Detected by ${result.detector}`,
+        })
       }
     }
 
     // Sort by confidence (highest first)
-    return suggestions.sort((a, b) => b.confidence - a.confidence);
+    return suggestions.sort((a, b) => b.confidence - a.confidence)
   }
 
   /**
@@ -247,10 +247,10 @@ export class PlatformDetector {
    * @param detector Custom platform detector
    */
   addDetector(detector: IPlatformDetector): void {
-    this.detectors.push(detector);
+    this.detectors.push(detector)
 
     // Re-sort by confidence (highest first)
-    this.detectors.sort((a, b) => b.confidence - a.confidence);
+    this.detectors.sort((a, b) => b.confidence - a.confidence)
   }
 
   /**
@@ -258,9 +258,7 @@ export class PlatformDetector {
    * @param detectorName Name of detector class to remove
    */
   removeDetector(detectorName: string): void {
-    this.detectors = this.detectors.filter(
-      detector => detector.constructor.name !== detectorName
-    );
+    this.detectors = this.detectors.filter(detector => detector.constructor.name !== detectorName)
   }
 
   /**
@@ -269,7 +267,7 @@ export class PlatformDetector {
    * @returns True if credentials are valid for at least one platform
    */
   isValidCredentials(credentials: any): boolean {
-    return this.detectPlatform(credentials) !== null;
+    return this.detectPlatform(credentials) !== null
   }
 
   /**
@@ -278,50 +276,50 @@ export class PlatformDetector {
    * @returns Detailed validation report
    */
   generateValidationReport(credentials: any): {
-    isValid: boolean;
-    detectedPlatform: Platform | null;
+    isValid: boolean
+    detectedPlatform: Platform | null
     allResults: Array<{
-      platform: Platform | null;
-      confidence: number;
-      detector: string;
-    }>;
+      platform: Platform | null
+      confidence: number
+      detector: string
+    }>
     suggestions: Array<{
-      platform: Platform;
-      confidence: number;
-      reason: string;
-    }>;
-    issues: string[];
+      platform: Platform
+      confidence: number
+      reason: string
+    }>
+    issues: string[]
   } {
-    const detectedPlatform = this.detectPlatform(credentials);
-    const allResults = this.getAllDetectionResults(credentials);
-    const suggestions = this.getSuggestedPlatforms(credentials);
-    const issues = [];
+    const detectedPlatform = this.detectPlatform(credentials)
+    const allResults = this.getAllDetectionResults(credentials)
+    const suggestions = this.getSuggestedPlatforms(credentials)
+    const issues = []
 
     // Check for common issues
     if (!credentials) {
-      issues.push('No credentials provided');
+      issues.push('No credentials provided')
     } else if (typeof credentials !== 'object') {
-      issues.push('Credentials must be an object');
+      issues.push('Credentials must be an object')
     } else {
       if (!detectedPlatform) {
-        issues.push('Could not detect platform from credentials');
+        issues.push('Could not detect platform from credentials')
       }
 
       if (!credentials.type) {
-        issues.push('Missing credential type');
+        issues.push('Missing credential type')
       }
 
       // Platform-specific validation
       if (credentials.type === 'ed25519' && !credentials.privateKey) {
-        issues.push('Ed25519 credentials missing privateKey');
+        issues.push('Ed25519 credentials missing privateKey')
       }
 
       if (credentials.type === 'eip191' && !credentials.privateKey) {
-        issues.push('EIP-191 credentials missing privateKey');
+        issues.push('EIP-191 credentials missing privateKey')
       }
 
       if (credentials.type === 'hmac' && (!credentials.apiKey || !credentials.secretKey)) {
-        issues.push('HMAC credentials missing apiKey or secretKey');
+        issues.push('HMAC credentials missing apiKey or secretKey')
       }
     }
 
@@ -330,7 +328,7 @@ export class PlatformDetector {
       detectedPlatform,
       allResults,
       suggestions,
-      issues
-    };
+      issues,
+    }
   }
-}
+}

+ 136 - 142
src/core/credential-manager/SignerFactory.ts

@@ -6,34 +6,41 @@
  * signing implementations (Pacifica, Binance, Aster).
  */
 
-import { Platform, Account, SignResult, Credentials } from '../../types/credential.js';
-import { CredentialManagerError, ErrorType } from '../../types/credential.js';
-import { PlatformDetector } from './PlatformDetector.js';
+import {
+  Platform,
+  Account,
+  SignResult,
+  Credentials,
+  CredentialManagerError,
+  ErrorType,
+} from '../../types/credential.js'
+
+import { PlatformDetector } from './PlatformDetector.js'
 
 // Import platform-specific signers
-import { PacificaSigner } from './signers/PacificaSigner.js';
-import { BinanceSigner } from './signers/BinanceSigner.js';
-import { AsterSigner } from './signers/AsterSigner.js';
+import { AsterSigner } from './signers/AsterSigner.js'
+import { BinanceSigner } from './signers/BinanceSigner.js'
+import { PacificaSigner } from './signers/PacificaSigner.js'
 
 // ============================================================================
 // Types and Interfaces
 // ============================================================================
 
 export interface ISignerStrategy {
-  readonly platform: Platform;
-  registerAccount(accountId: string, credentials: Credentials): Promise<void> | void;
-  removeAccount(accountId: string): boolean;
-  sign(accountId: string, message: Uint8Array): Promise<SignResult>;
-  verify(accountId: string, message: Uint8Array, signature: string): Promise<boolean>;
-  getMetrics?(): any;
-  resetMetrics?(): void;
+  readonly platform: Platform
+  registerAccount(accountId: string, credentials: Credentials): Promise<void> | void
+  removeAccount(accountId: string): boolean
+  sign(accountId: string, message: Uint8Array): Promise<SignResult>
+  verify(accountId: string, message: Uint8Array, signature: string): Promise<boolean>
+  getMetrics?(): any
+  resetMetrics?(): void
 }
 
 export interface SignerFactoryOptions {
-  enablePlatformDetection?: boolean;
-  platformDetector?: PlatformDetector;
-  enableMetrics?: boolean;
-  logErrors?: boolean;
+  enablePlatformDetection?: boolean
+  platformDetector?: PlatformDetector
+  enableMetrics?: boolean
+  logErrors?: boolean
 }
 
 // ============================================================================
@@ -41,26 +48,26 @@ export interface SignerFactoryOptions {
 // ============================================================================
 
 export class SignerFactory {
-  private strategies = new Map<Platform, ISignerStrategy>();
-  private platformDetector: PlatformDetector;
-  private options: Required<SignerFactoryOptions>;
+  private strategies = new Map<Platform, ISignerStrategy>()
+  private platformDetector: PlatformDetector
+  private options: Required<SignerFactoryOptions>
   private metrics = {
     totalSignRequests: 0,
     successfulSigns: 0,
     failedSigns: 0,
-    platformUsage: new Map<Platform, number>()
-  };
+    platformUsage: new Map<Platform, number>(),
+  }
 
   constructor(options: SignerFactoryOptions = {}) {
     this.options = {
       enablePlatformDetection: options.enablePlatformDetection ?? true,
       platformDetector: options.platformDetector ?? new PlatformDetector(),
       enableMetrics: options.enableMetrics ?? true,
-      logErrors: options.logErrors ?? true
-    };
+      logErrors: options.logErrors ?? true,
+    }
 
-    this.platformDetector = this.options.platformDetector;
-    this.initializeStrategies();
+    this.platformDetector = this.options.platformDetector
+    this.initializeStrategies()
   }
 
   /**
@@ -69,22 +76,21 @@ export class SignerFactory {
   private initializeStrategies(): void {
     try {
       // Initialize Pacifica signer
-      const pacificaSigner = new PacificaSigner();
-      this.registerStrategy(Platform.PACIFICA, pacificaSigner);
+      const pacificaSigner = new PacificaSigner()
+      this.registerStrategy(Platform.PACIFICA, pacificaSigner)
 
       // Initialize Binance signer
-      const binanceSigner = new BinanceSigner();
-      this.registerStrategy(Platform.BINANCE, binanceSigner);
+      const binanceSigner = new BinanceSigner()
+      this.registerStrategy(Platform.BINANCE, binanceSigner)
 
       // Initialize Aster signer
-      const asterSigner = new AsterSigner();
-      this.registerStrategy(Platform.ASTER, asterSigner);
-
+      const asterSigner = new AsterSigner()
+      this.registerStrategy(Platform.ASTER, asterSigner)
     } catch (error) {
       throw new CredentialManagerError(
         `Failed to initialize signing strategies: ${error.message}`,
-        ErrorType.SIGNATURE_ERROR
-      );
+        ErrorType.SIGNATURE_ERROR,
+      )
     }
   }
 
@@ -95,15 +101,15 @@ export class SignerFactory {
     if (strategy.platform !== platform) {
       throw new CredentialManagerError(
         `Strategy platform mismatch: expected ${platform}, got ${strategy.platform}`,
-        ErrorType.VALIDATION_ERROR
-      );
+        ErrorType.VALIDATION_ERROR,
+      )
     }
 
-    this.strategies.set(platform, strategy);
+    this.strategies.set(platform, strategy)
 
     // Initialize platform usage tracking
     if (this.options.enableMetrics && !this.metrics.platformUsage.has(platform)) {
-      this.metrics.platformUsage.set(platform, 0);
+      this.metrics.platformUsage.set(platform, 0)
     }
   }
 
@@ -111,14 +117,14 @@ export class SignerFactory {
    * Get strategy for a specific platform
    */
   getStrategy(platform: Platform): ISignerStrategy {
-    const strategy = this.strategies.get(platform);
+    const strategy = this.strategies.get(platform)
     if (!strategy) {
       throw new CredentialManagerError(
         `No signing strategy available for platform: ${platform}`,
-        ErrorType.PLATFORM_DETECTION_ERROR
-      );
+        ErrorType.PLATFORM_DETECTION_ERROR,
+      )
     }
-    return strategy;
+    return strategy
   }
 
   /**
@@ -127,26 +133,27 @@ export class SignerFactory {
   async registerAccount(account: Account): Promise<void> {
     try {
       // Detect platform if not explicitly specified or if detection is enabled
-      let platform = account.platform;
+      const platform = account.platform
 
       if (this.options.enablePlatformDetection) {
-        const detectedPlatform = this.platformDetector.detectPlatform(account.credentials);
+        const detectedPlatform = this.platformDetector.detectPlatform(account.credentials)
         if (detectedPlatform && detectedPlatform !== account.platform) {
           // Log platform mismatch but use the specified platform
           if (this.options.logErrors) {
-            console.warn(`Platform mismatch for account ${account.id}: specified ${account.platform}, detected ${detectedPlatform}`);
+            console.warn(
+              `Platform mismatch for account ${account.id}: specified ${account.platform}, detected ${detectedPlatform}`,
+            )
           }
         }
       }
 
-      const strategy = this.getStrategy(platform);
-      await strategy.registerAccount(account.id, account.credentials);
-
+      const strategy = this.getStrategy(platform)
+      await strategy.registerAccount(account.id, account.credentials)
     } catch (error) {
       if (this.options.logErrors) {
-        console.error(`Failed to register account ${account.id}:`, error);
+        console.error(`Failed to register account ${account.id}:`, error)
       }
-      throw error;
+      throw error
     }
   }
 
@@ -154,85 +161,78 @@ export class SignerFactory {
    * Remove an account from all signers
    */
   removeAccount(accountId: string): boolean {
-    let removed = false;
+    let removed = false
 
     for (const strategy of this.strategies.values()) {
-      const wasRemoved = strategy.removeAccount(accountId);
-      removed = removed || wasRemoved;
+      const wasRemoved = strategy.removeAccount(accountId)
+      removed = removed || wasRemoved
     }
 
-    return removed;
+    return removed
   }
 
   /**
    * Sign a message using the appropriate platform strategy
    */
   async sign(accountId: string, message: Uint8Array, platform?: Platform): Promise<SignResult> {
-    this.updateMetrics('sign-request');
+    this.updateMetrics('sign-request')
 
     try {
       // If platform is not specified, try to find it from registered accounts
-      let targetPlatform = platform;
+      let targetPlatform = platform
 
       if (!targetPlatform) {
-        targetPlatform = await this.findAccountPlatform(accountId);
+        targetPlatform = await this.findAccountPlatform(accountId)
       }
 
-      const strategy = this.getStrategy(targetPlatform);
-      const result = await strategy.sign(accountId, message);
+      const strategy = this.getStrategy(targetPlatform)
+      const result = await strategy.sign(accountId, message)
 
       if (result.success) {
-        this.updateMetrics('sign-success', targetPlatform);
+        this.updateMetrics('sign-success', targetPlatform)
       } else {
-        this.updateMetrics('sign-failure');
+        this.updateMetrics('sign-failure')
         if (this.options.logErrors && result.error) {
-          console.error(`Signing failed for account ${accountId}:`, result.error);
+          console.error(`Signing failed for account ${accountId}:`, result.error)
         }
       }
 
-      return result;
-
+      return result
     } catch (error) {
-      this.updateMetrics('sign-failure');
+      this.updateMetrics('sign-failure')
 
       if (this.options.logErrors) {
-        console.error(`Sign operation failed for account ${accountId}:`, error);
+        console.error(`Sign operation failed for account ${accountId}:`, error)
       }
 
       return {
         success: false,
         algorithm: 'unknown',
         timestamp: new Date(),
-        error: error instanceof Error ? error.message : 'Unknown signing error'
-      };
+        error: error instanceof Error ? error.message : 'Unknown signing error',
+      }
     }
   }
 
   /**
    * Verify a signature using the appropriate platform strategy
    */
-  async verify(
-    accountId: string,
-    message: Uint8Array,
-    signature: string,
-    platform?: Platform
-  ): Promise<boolean> {
+  async verify(accountId: string, message: Uint8Array, signature: string, platform?: Platform): Promise<boolean> {
     try {
       // If platform is not specified, try to find it from registered accounts
-      let targetPlatform = platform;
+      let targetPlatform = platform
 
       if (!targetPlatform) {
-        targetPlatform = await this.findAccountPlatform(accountId);
+        targetPlatform = await this.findAccountPlatform(accountId)
       }
 
-      const strategy = this.getStrategy(targetPlatform);
-      return await strategy.verify(accountId, message, signature);
-
+      const strategy = this.getStrategy(targetPlatform)
+      return await strategy.verify(accountId, message, signature)
     } catch (error) {
       if (this.options.logErrors) {
-        console.error(`Verification failed for account ${accountId}:`, error);
+        console.error(`Verification failed for account ${accountId}:`, error)
       }
-      return false;
+      return false
     }
   }
 
@@ -240,14 +240,14 @@ export class SignerFactory {
    * Get list of supported platforms
    */
   getSupportedPlatforms(): Platform[] {
-    return Array.from(this.strategies.keys());
+    return Array.from(this.strategies.keys())
   }
 
   /**
    * Check if a platform is supported
    */
   isPlatformSupported(platform: Platform): boolean {
-    return this.strategies.has(platform);
+    return this.strategies.has(platform)
   }
 
   /**
@@ -255,15 +255,15 @@ export class SignerFactory {
    */
   getMetrics() {
     if (!this.options.enableMetrics) {
-      return null;
+      return null
     }
 
-    const platformMetrics: Record<string, any> = {};
+    const platformMetrics: Record<string, any> = {}
 
     // Collect metrics from individual strategies
     for (const [platform, strategy] of this.strategies.entries()) {
       if (strategy.getMetrics) {
-        platformMetrics[platform] = strategy.getMetrics();
+        platformMetrics[platform] = strategy.getMetrics()
       }
     }
 
@@ -272,13 +272,12 @@ export class SignerFactory {
         totalSignRequests: this.metrics.totalSignRequests,
         successfulSigns: this.metrics.successfulSigns,
         failedSigns: this.metrics.failedSigns,
-        successRate: this.metrics.totalSignRequests > 0
-          ? this.metrics.successfulSigns / this.metrics.totalSignRequests
-          : 0,
-        platformUsage: Object.fromEntries(this.metrics.platformUsage)
+        successRate:
+          this.metrics.totalSignRequests > 0 ? this.metrics.successfulSigns / this.metrics.totalSignRequests : 0,
+        platformUsage: Object.fromEntries(this.metrics.platformUsage),
       },
-      strategies: platformMetrics
-    };
+      strategies: platformMetrics,
+    }
   }
 
   /**
@@ -286,20 +285,20 @@ export class SignerFactory {
    */
   resetMetrics(): void {
     if (!this.options.enableMetrics) {
-      return;
+      return
     }
 
     this.metrics = {
       totalSignRequests: 0,
       successfulSigns: 0,
       failedSigns: 0,
-      platformUsage: new Map<Platform, number>()
-    };
+      platformUsage: new Map<Platform, number>(),
+    }
 
     // Reset strategy metrics
     for (const strategy of this.strategies.values()) {
       if (strategy.resetMetrics) {
-        strategy.resetMetrics();
+        strategy.resetMetrics()
       }
     }
   }
@@ -308,56 +307,54 @@ export class SignerFactory {
    * Get detailed platform information
    */
   getPlatformInfo(platform: Platform): any {
-    const strategy = this.strategies.get(platform);
+    const strategy = this.strategies.get(platform)
     if (!strategy) {
-      return null;
+      return null
     }
 
     return {
       platform: strategy.platform,
       hasMetrics: typeof strategy.getMetrics === 'function',
       supportsReset: typeof strategy.resetMetrics === 'function',
-      isAvailable: true
-    };
+      isAvailable: true,
+    }
   }
 
   /**
    * Batch register multiple accounts
    */
   async registerAccounts(accounts: Account[]): Promise<void> {
-    const errors: Error[] = [];
+    const errors: Error[] = []
 
     // Process accounts in parallel by platform
-    const platformGroups = new Map<Platform, Account[]>();
+    const platformGroups = new Map<Platform, Account[]>()
 
     for (const account of accounts) {
-      const group = platformGroups.get(account.platform) || [];
-      group.push(account);
-      platformGroups.set(account.platform, group);
+      const group = platformGroups.get(account.platform) || []
+      group.push(account)
+      platformGroups.set(account.platform, group)
     }
 
     // Register accounts for each platform
-    const registrationPromises = Array.from(platformGroups.entries()).map(
-      async ([platform, platformAccounts]) => {
-        const strategy = this.getStrategy(platform);
-
-        for (const account of platformAccounts) {
-          try {
-            await strategy.registerAccount(account.id, account.credentials);
-          } catch (error) {
-            errors.push(new Error(`Failed to register ${account.id}: ${error.message}`));
-          }
+    const registrationPromises = Array.from(platformGroups.entries()).map(async ([platform, platformAccounts]) => {
+      const strategy = this.getStrategy(platform)
+
+      for (const account of platformAccounts) {
+        try {
+          await strategy.registerAccount(account.id, account.credentials)
+        } catch (error) {
+          errors.push(new Error(`Failed to register ${account.id}: ${error.message}`))
         }
       }
-    );
+    })
 
-    await Promise.all(registrationPromises);
+    await Promise.all(registrationPromises)
 
     if (errors.length > 0) {
       throw new CredentialManagerError(
         `Failed to register ${errors.length} accounts: ${errors.map(e => e.message).join(', ')}`,
-        ErrorType.VALIDATION_ERROR
-      );
+        ErrorType.VALIDATION_ERROR,
+      )
     }
   }
 
@@ -375,18 +372,15 @@ export class SignerFactory {
         // Try a lightweight operation to check if account exists
         // This is a simplified approach - in production, you might want
         // to maintain an account-to-platform mapping
-        await strategy.sign(accountId, new Uint8Array(0));
-        return platform;
+        await strategy.sign(accountId, new Uint8Array(0))
+        return platform
       } catch (error) {
         // Account not found on this platform, continue
-        continue;
+        continue
       }
     }
 
-    throw new CredentialManagerError(
-      `Account ${accountId} not found on any platform`,
-      ErrorType.SIGNATURE_ERROR
-    );
+    throw new CredentialManagerError(`Account ${accountId} not found on any platform`, ErrorType.SIGNATURE_ERROR)
   }
 
   /**
@@ -394,23 +388,23 @@ export class SignerFactory {
    */
   private updateMetrics(type: 'sign-request' | 'sign-success' | 'sign-failure', platform?: Platform): void {
     if (!this.options.enableMetrics) {
-      return;
+      return
     }
 
     switch (type) {
       case 'sign-request':
-        this.metrics.totalSignRequests++;
-        break;
+        this.metrics.totalSignRequests++
+        break
       case 'sign-success':
-        this.metrics.successfulSigns++;
+        this.metrics.successfulSigns++
         if (platform) {
-          const currentCount = this.metrics.platformUsage.get(platform) || 0;
-          this.metrics.platformUsage.set(platform, currentCount + 1);
+          const currentCount = this.metrics.platformUsage.get(platform) || 0
+          this.metrics.platformUsage.set(platform, currentCount + 1)
         }
-        break;
+        break
       case 'sign-failure':
-        this.metrics.failedSigns++;
-        break;
+        this.metrics.failedSigns++
+        break
     }
   }
 }
@@ -423,7 +417,7 @@ export class SignerFactory {
  * Create a pre-configured signer factory instance
  */
 export function createSignerFactory(options?: SignerFactoryOptions): SignerFactory {
-  return new SignerFactory(options);
+  return new SignerFactory(options)
 }
 
 /**
@@ -433,8 +427,8 @@ export function createDefaultSignerFactory(): SignerFactory {
   return new SignerFactory({
     enablePlatformDetection: true,
     enableMetrics: true,
-    logErrors: true
-  });
+    logErrors: true,
+  })
 }
 
 /**
@@ -444,12 +438,12 @@ export function createTestSignerFactory(): SignerFactory {
   return new SignerFactory({
     enablePlatformDetection: true,
     enableMetrics: false,
-    logErrors: false
-  });
+    logErrors: false,
+  })
 }
 
 // ============================================================================
 // Export
 // ============================================================================
 
-export default SignerFactory;
+export default SignerFactory

+ 65 - 81
src/core/credential-manager/index.ts

@@ -7,92 +7,77 @@
  */
 
 // Main classes
-export { CredentialManager } from './CredentialManager';
-export { ConfigLoader } from './ConfigLoader';
-export { CredentialValidator } from './CredentialValidator';
-export { PlatformDetector } from './PlatformDetector';
+export { CredentialManager } from './CredentialManager'
+export { ConfigLoader } from './ConfigLoader'
+export { CredentialValidator } from './CredentialValidator'
+export { PlatformDetector } from './PlatformDetector'
 
 // Platform-specific signers
-export { PacificaSigner } from './signers/PacificaSigner';
+export { PacificaSigner } from './signers/PacificaSigner'
 
 // Platform detectors
-export {
-  PacificaDetector,
-  AsterDetector,
-  BinanceDetector
-} from './PlatformDetector';
+export { PacificaDetector, AsterDetector, BinanceDetector } from './PlatformDetector'
 
 // Utility classes
-export {
-  PacificaKeyUtils,
-  PacificaSignerMetrics
-} from './signers/PacificaSigner';
+export { PacificaKeyUtils, PacificaSignerMetrics } from './signers/PacificaSigner'
 
 // Re-export all types from the types module
-export * from '@/types/credential';
+export * from '@/types/credential'
 
 // Constants and defaults
-export const CREDENTIAL_MANAGER_VERSION = '1.0.0';
+export const CREDENTIAL_MANAGER_VERSION = '1.0.0'
 
 export const DEFAULT_CONFIG_PATHS = [
   './credentials.json',
   './config/credentials.json',
   './credentials.yaml',
-  './config/credentials.yaml'
-];
+  './config/credentials.yaml',
+]
 
-export const SUPPORTED_PLATFORMS = [
-  'PACIFICA',
-  'ASTER',
-  'BINANCE'
-] as const;
+export const SUPPORTED_PLATFORMS = ['PACIFICA', 'ASTER', 'BINANCE'] as const
 
-export const SUPPORTED_SIGNATURE_TYPES = [
-  'ed25519',
-  'eip191',
-  'hmac-sha256'
-] as const;
+export const SUPPORTED_SIGNATURE_TYPES = ['ed25519', 'eip191', 'hmac-sha256'] as const
 
 // Performance constants
 export const PERFORMANCE_REQUIREMENTS = {
   CONFIG_LOAD_TIME_MS: 100,
   SIGNING_TIME_MS: 50,
   MEMORY_LIMIT_MB: 50,
-  MIN_SUPPORTED_ACCOUNTS: 50
-} as const;
+  MIN_SUPPORTED_ACCOUNTS: 50,
+} as const
 
 // Factory function for easy initialization
 export function createCredentialManager(): CredentialManager {
-  return new CredentialManager();
+  return new CredentialManager()
 }
 
 // Convenience function to create and load configuration
 export async function createCredentialManagerWithConfig(configPath: string): Promise<{
-  manager: CredentialManager;
-  loadResult: import('@/types/credential').LoadResult;
+  manager: CredentialManager
+  loadResult: import('@/types/credential').LoadResult
 }> {
-  const manager = new CredentialManager();
-  const loadResult = await manager.loadConfig(configPath);
+  const manager = new CredentialManager()
+  const loadResult = await manager.loadConfig(configPath)
 
   return {
     manager,
-    loadResult
-  };
+    loadResult,
+  }
 }
 
 // Helper function to validate configuration file before loading
 export async function validateConfigFile(configPath: string): Promise<{
-  isValid: boolean;
-  errors: string[];
-  warnings: string[];
-  accountCount: number;
-  supportedPlatforms: string[];
+  isValid: boolean
+  errors: string[]
+  warnings: string[]
+  accountCount: number
+  supportedPlatforms: string[]
 }> {
-  const configLoader = new ConfigLoader();
-  const validator = new CredentialValidator();
+  const configLoader = new ConfigLoader()
+  const validator = new CredentialValidator()
 
   try {
-    const loadResult = await configLoader.loadConfig(configPath);
+    const loadResult = await configLoader.loadConfig(configPath)
 
     if (!loadResult.success) {
       return {
@@ -100,8 +85,8 @@ export async function validateConfigFile(configPath: string): Promise<{
         errors: loadResult.errors || ['Configuration load failed'],
         warnings: [],
         accountCount: 0,
-        supportedPlatforms: []
-      };
+        supportedPlatforms: [],
+      }
     }
 
     const validationReport = validator.generateValidationReport(
@@ -111,95 +96,94 @@ export async function validateConfigFile(configPath: string): Promise<{
         name: account.name,
         credentials: account.credentials,
         enabled: account.enabled,
-        metadata: account.metadata
-      }))
-    );
+        metadata: account.metadata,
+      })),
+    )
 
     const supportedPlatforms = Object.entries(validationReport.platformCounts)
       .filter(([_, count]) => count > 0)
-      .map(([platform, _]) => platform);
+      .map(([platform, _]) => platform)
 
     return {
       isValid: validationReport.isValid,
       errors: validationReport.globalErrors,
       warnings: validationReport.globalWarnings,
       accountCount: validationReport.validAccounts,
-      supportedPlatforms
-    };
-
+      supportedPlatforms,
+    }
   } catch (error) {
     return {
       isValid: false,
       errors: [`Failed to validate configuration: ${error instanceof Error ? error.message : 'Unknown error'}`],
       warnings: [],
       accountCount: 0,
-      supportedPlatforms: []
-    };
+      supportedPlatforms: [],
+    }
   }
 }
 
 // Helper function to generate configuration template
 export function generateConfigTemplate(): import('@/types/credential').ConfigFile {
-  const configLoader = new ConfigLoader();
-  return configLoader.getConfigTemplate();
+  const configLoader = new ConfigLoader()
+  return configLoader.getConfigTemplate()
 }
 
 // Helper function to check system requirements
 export function checkSystemRequirements(): {
-  nodejs: { supported: boolean; version?: string; };
-  typescript: { supported: boolean; };
-  memory: { available: boolean; usage?: number; };
+  nodejs: { supported: boolean; version?: string }
+  typescript: { supported: boolean }
+  memory: { available: boolean; usage?: number }
   dependencies: {
-    tweetnacl: boolean;
-  };
+    tweetnacl: boolean
+  }
 } {
   const requirements = {
     nodejs: { supported: false },
     typescript: { supported: false },
     memory: { available: false },
     dependencies: {
-      tweetnacl: false
-    }
-  };
+      tweetnacl: false,
+    },
+  }
 
   // Check Node.js version
   if (process.version) {
-    const version = process.version;
-    const majorVersion = parseInt(version.slice(1).split('.')[0]);
+    const version = process.version
+    const majorVersion = parseInt(version.slice(1).split('.')[0])
     requirements.nodejs = {
       supported: majorVersion >= 18,
-      version
-    };
+      version,
+    }
   }
 
   // Check TypeScript (basic check)
   try {
-    require.resolve('typescript');
-    requirements.typescript.supported = true;
+    require.resolve('typescript')
+    requirements.typescript.supported = true
   } catch (error) {
     // TypeScript not available
   }
 
   // Check memory
   if (process.memoryUsage) {
-    const memUsage = process.memoryUsage();
+    const memUsage = process.memoryUsage()
     requirements.memory = {
-      available: memUsage.heapUsed < (PERFORMANCE_REQUIREMENTS.MEMORY_LIMIT_MB * 1024 * 1024),
-      usage: Math.round(memUsage.heapUsed / (1024 * 1024))
-    };
+      available: memUsage.heapUsed < PERFORMANCE_REQUIREMENTS.MEMORY_LIMIT_MB * 1024 * 1024,
+      usage: Math.round(memUsage.heapUsed / (1024 * 1024)),
+    }
   }
 
   // Check dependencies
   try {
-    require.resolve('tweetnacl');
-    requirements.dependencies.tweetnacl = true;
+    require.resolve('tweetnacl')
+    requirements.dependencies.tweetnacl = true
   } catch (error) {
     // tweetnacl not available
   }
 
-  return requirements;
+  return requirements
 }
 
 // Main export - default credential manager instance
-const defaultManager = new CredentialManager();
-export default defaultManager;
+const defaultManager = new CredentialManager()
+export default defaultManager

+ 166 - 206
src/core/credential-manager/signers/AsterSigner.ts

@@ -5,70 +5,70 @@
  * according to Ethereum standards and Aster Network specifications.
  */
 
-import { keccak256 } from 'js-sha3';
-import { Platform, Credentials, AsterCredentials } from '../../../types/credential.js';
-import { CredentialManagerError, ErrorType } from '../../../types/credential.js';
+import { keccak256 } from 'js-sha3'
+
+import { Platform, Credentials, AsterCredentials, CredentialManagerError, ErrorType } from '@/types/credential'
 
 // Dynamic import for secp256k1 to handle ESM/CJS compatibility
-let secp256k1: any;
+let secp256k1: any
 
 // ============================================================================
 // Types and Interfaces
 // ============================================================================
 
 export interface AsterSignRequest {
-  accountId: string;
-  transaction: AsterTransaction;
-  options?: AsterSignOptions;
+  accountId: string
+  transaction: AsterTransaction
+  options?: AsterSignOptions
 }
 
 export interface AsterMessageSignRequest {
-  accountId: string;
-  message: string | Uint8Array;
-  options?: AsterSignOptions;
+  accountId: string
+  message: string | Uint8Array
+  options?: AsterSignOptions
 }
 
 export interface AsterSignOptions {
-  timeout?: number;
-  chainId?: number;
-  gasLimit?: string;
-  gasPrice?: string;
-  nonce?: number;
+  timeout?: number
+  chainId?: number
+  gasLimit?: string
+  gasPrice?: string
+  nonce?: number
 }
 
 export interface AsterTransaction {
-  to: string;
-  value?: string;
-  data?: string;
-  gasLimit?: string;
-  gasPrice?: string;
-  nonce?: number;
-  chainId?: number;
+  to: string
+  value?: string
+  data?: string
+  gasLimit?: string
+  gasPrice?: string
+  nonce?: number
+  chainId?: number
 }
 
 export interface AsterSignResponse {
-  success: boolean;
-  signature: string;
-  algorithm: 'ecdsa-secp256k1' | 'eip-191';
-  address: string;
-  chainId?: number;
-  txHash?: string;
-  timestamp: Date;
-  error?: string;
+  success: boolean
+  signature: string
+  algorithm: 'ecdsa-secp256k1' | 'eip-191'
+  address: string
+  chainId?: number
+  txHash?: string
+  timestamp: Date
+  error?: string
 }
 
 export interface AsterVerifyRequest {
-  message: string | Uint8Array;
-  signature: string;
-  address: string;
-  algorithm?: 'ecdsa-secp256k1' | 'eip-191';
+  message: string | Uint8Array
+  signature: string
+  address: string
+  algorithm?: 'ecdsa-secp256k1' | 'eip-191'
 }
 
 export interface AsterVerifyResponse {
-  valid: boolean;
-  algorithm: 'ecdsa-secp256k1' | 'eip-191';
-  address: string;
-  timestamp: Date;
+  valid: boolean
+  algorithm: 'ecdsa-secp256k1' | 'eip-191'
+  address: string
+  timestamp: Date
 }
 
 // ============================================================================
@@ -76,19 +76,19 @@ export interface AsterVerifyResponse {
 // ============================================================================
 
 export class AsterSigner {
-  readonly platform = Platform.ASTER;
+  readonly platform = Platform.ASTER
 
-  private accounts = new Map<string, { credentials: AsterCredentials; address: string }>();
+  private accounts = new Map<string, { credentials: AsterCredentials; address: string }>()
   private signMetrics = {
     totalSigns: 0,
     successfulSigns: 0,
     failedSigns: 0,
-    totalTime: 0
-  };
+    totalTime: 0,
+  }
 
   constructor() {
     // Initialize with empty accounts map
-    this.initializeSecp256k1();
+    this.initializeSecp256k1()
   }
 
   /**
@@ -97,17 +97,17 @@ export class AsterSigner {
   private async initializeSecp256k1(): Promise<void> {
     try {
       // Try to import noble-secp256k1 which is preferred for TypeScript
-      const { secp256k1: nobleSecp } = await import('@noble/secp256k1');
-      secp256k1 = nobleSecp;
+      const { secp256k1: nobleSecp } = await import('@noble/secp256k1')
+      secp256k1 = nobleSecp
     } catch (error) {
       // Fallback to native secp256k1 if available
       try {
-        secp256k1 = await import('secp256k1');
+        secp256k1 = await import('secp256k1')
       } catch (fallbackError) {
         throw new CredentialManagerError(
           'No secp256k1 library available. Please install @noble/secp256k1 or secp256k1',
-          ErrorType.SIGNATURE_ERROR
-        );
+          ErrorType.SIGNATURE_ERROR,
+        )
       }
     }
   }
@@ -117,52 +117,46 @@ export class AsterSigner {
    */
   async registerAccount(accountId: string, credentials: AsterCredentials): Promise<void> {
     if (!this.validateCredentials(credentials)) {
-      throw new CredentialManagerError(
-        `Invalid Aster credentials for account ${accountId}`,
-        ErrorType.VALIDATION_ERROR
-      );
+      throw new CredentialManagerError(`Invalid Aster credentials for account ${accountId}`, ErrorType.VALIDATION_ERROR)
     }
 
-    const address = await this.deriveAddress(credentials.privateKey);
-    this.accounts.set(accountId, { credentials, address });
+    const address = await this.deriveAddress(credentials.privateKey)
+    this.accounts.set(accountId, { credentials, address })
   }
 
   /**
    * Remove an account
    */
   removeAccount(accountId: string): boolean {
-    return this.accounts.delete(accountId);
+    return this.accounts.delete(accountId)
   }
 
   /**
    * Sign Aster Network transaction
    */
   async signTransaction(request: AsterSignRequest): Promise<AsterSignResponse> {
-    const startTime = Date.now();
-    this.signMetrics.totalSigns++;
+    const startTime = Date.now()
+    this.signMetrics.totalSigns++
 
     try {
-      const account = this.accounts.get(request.accountId);
+      const account = this.accounts.get(request.accountId)
       if (!account) {
-        throw new CredentialManagerError(
-          `Account ${request.accountId} not found`,
-          ErrorType.SIGNATURE_ERROR
-        );
+        throw new CredentialManagerError(`Account ${request.accountId} not found`, ErrorType.SIGNATURE_ERROR)
       }
 
-      const { credentials, address } = account;
-      const transaction = this.prepareTransaction(request.transaction, request.options);
+      const { credentials, address } = account
+      const transaction = this.prepareTransaction(request.transaction, request.options)
 
       // Serialize transaction for signing
-      const serializedTx = this.serializeTransaction(transaction);
-      const txHash = this.keccak256Hash(serializedTx);
+      const serializedTx = this.serializeTransaction(transaction)
+      const txHash = this.keccak256Hash(serializedTx)
 
       // Sign with ECDSA secp256k1
-      const signature = await this.signHash(txHash, credentials.privateKey);
+      const signature = await this.signHash(txHash, credentials.privateKey)
 
-      const duration = Date.now() - startTime;
-      this.signMetrics.successfulSigns++;
-      this.signMetrics.totalTime += duration;
+      const duration = Date.now() - startTime
+      this.signMetrics.successfulSigns++
+      this.signMetrics.totalTime += duration
 
       return {
         success: true,
@@ -171,13 +165,12 @@ export class AsterSigner {
         address,
         chainId: transaction.chainId,
         txHash: `0x${txHash}`,
-        timestamp: new Date()
-      };
-
+        timestamp: new Date(),
+      }
     } catch (error) {
-      const duration = Date.now() - startTime;
-      this.signMetrics.failedSigns++;
-      this.signMetrics.totalTime += duration;
+      const duration = Date.now() - startTime
+      this.signMetrics.failedSigns++
+      this.signMetrics.totalTime += duration
 
       return {
         success: false,
@@ -185,8 +178,8 @@ export class AsterSigner {
         algorithm: 'ecdsa-secp256k1',
         address: '',
         timestamp: new Date(),
-        error: error instanceof Error ? error.message : 'Unknown signing error'
-      };
+        error: error instanceof Error ? error.message : 'Unknown signing error',
+      }
     }
   }
 
@@ -194,48 +187,42 @@ export class AsterSigner {
    * Sign arbitrary message using EIP-191
    */
   async signMessage(request: AsterMessageSignRequest): Promise<AsterSignResponse> {
-    const startTime = Date.now();
-    this.signMetrics.totalSigns++;
+    const startTime = Date.now()
+    this.signMetrics.totalSigns++
 
     try {
-      const account = this.accounts.get(request.accountId);
+      const account = this.accounts.get(request.accountId)
       if (!account) {
-        throw new CredentialManagerError(
-          `Account ${request.accountId} not found`,
-          ErrorType.SIGNATURE_ERROR
-        );
+        throw new CredentialManagerError(`Account ${request.accountId} not found`, ErrorType.SIGNATURE_ERROR)
       }
 
-      const { credentials, address } = account;
+      const { credentials, address } = account
 
       // Convert message to string if it's binary
-      const message = typeof request.message === 'string'
-        ? request.message
-        : new TextDecoder().decode(request.message);
+      const message = typeof request.message === 'string' ? request.message : new TextDecoder().decode(request.message)
 
       // Create EIP-191 formatted message
-      const eip191Message = this.formatEip191Message(message);
-      const messageHash = this.keccak256Hash(eip191Message);
+      const eip191Message = this.formatEip191Message(message)
+      const messageHash = this.keccak256Hash(eip191Message)
 
       // Sign with ECDSA secp256k1
-      const signature = await this.signHash(messageHash, credentials.privateKey);
+      const signature = await this.signHash(messageHash, credentials.privateKey)
 
-      const duration = Date.now() - startTime;
-      this.signMetrics.successfulSigns++;
-      this.signMetrics.totalTime += duration;
+      const duration = Date.now() - startTime
+      this.signMetrics.successfulSigns++
+      this.signMetrics.totalTime += duration
 
       return {
         success: true,
         signature,
         algorithm: 'eip-191',
         address,
-        timestamp: new Date()
-      };
-
+        timestamp: new Date(),
+      }
     } catch (error) {
-      const duration = Date.now() - startTime;
-      this.signMetrics.failedSigns++;
-      this.signMetrics.totalTime += duration;
+      const duration = Date.now() - startTime
+      this.signMetrics.failedSigns++
+      this.signMetrics.totalTime += duration
 
       return {
         success: false,
@@ -243,8 +230,8 @@ export class AsterSigner {
         algorithm: 'eip-191',
         address: '',
         timestamp: new Date(),
-        error: error instanceof Error ? error.message : 'Unknown signing error'
-      };
+        error: error instanceof Error ? error.message : 'Unknown signing error',
+      }
     }
   }
 
@@ -253,41 +240,34 @@ export class AsterSigner {
    */
   async verifySignature(request: AsterVerifyRequest): Promise<AsterVerifyResponse> {
     try {
-      const message = typeof request.message === 'string'
-        ? request.message
-        : new TextDecoder().decode(request.message);
+      const message = typeof request.message === 'string' ? request.message : new TextDecoder().decode(request.message)
 
-      let messageHash: string;
+      let messageHash: string
 
       if (request.algorithm === 'eip-191' || !request.algorithm) {
         // Default to EIP-191 for message verification
-        const eip191Message = this.formatEip191Message(message);
-        messageHash = this.keccak256Hash(eip191Message);
+        const eip191Message = this.formatEip191Message(message)
+        messageHash = this.keccak256Hash(eip191Message)
       } else {
         // Direct message hash for transaction verification
-        messageHash = this.keccak256Hash(message);
+        messageHash = this.keccak256Hash(message)
       }
 
-      const valid = await this.verifyEcdsaSignature(
-        messageHash,
-        request.signature,
-        request.address
-      );
+      const valid = await this.verifyEcdsaSignature(messageHash, request.signature, request.address)
 
       return {
         valid,
         algorithm: request.algorithm || 'eip-191',
         address: request.address,
-        timestamp: new Date()
-      };
-
+        timestamp: new Date(),
+      }
     } catch (error) {
       return {
         valid: false,
         algorithm: request.algorithm || 'eip-191',
         address: request.address,
-        timestamp: new Date()
-      };
+        timestamp: new Date(),
+      }
     }
   }
 
@@ -295,15 +275,12 @@ export class AsterSigner {
    * Get Ethereum address for account
    */
   async getAddress(accountId: string): Promise<string> {
-    const account = this.accounts.get(accountId);
+    const account = this.accounts.get(accountId)
     if (!account) {
-      throw new CredentialManagerError(
-        `Account ${accountId} not found`,
-        ErrorType.SIGNATURE_ERROR
-      );
+      throw new CredentialManagerError(`Account ${accountId} not found`, ErrorType.SIGNATURE_ERROR)
     }
 
-    return account.address;
+    return account.address
   }
 
   /**
@@ -311,27 +288,23 @@ export class AsterSigner {
    */
   async signBatch(requests: AsterSignRequest[]): Promise<AsterSignResponse[]> {
     // Process requests in parallel for better performance
-    const promises = requests.map(request => this.signTransaction(request));
-    return Promise.all(promises);
+    const promises = requests.map(request => this.signTransaction(request))
+    return Promise.all(promises)
   }
 
   /**
    * Get signing metrics for monitoring
    */
   getMetrics() {
-    const avgTime = this.signMetrics.totalSigns > 0
-      ? this.signMetrics.totalTime / this.signMetrics.totalSigns
-      : 0;
+    const avgTime = this.signMetrics.totalSigns > 0 ? this.signMetrics.totalTime / this.signMetrics.totalSigns : 0
 
     return {
       totalSigns: this.signMetrics.totalSigns,
       successfulSigns: this.signMetrics.successfulSigns,
       failedSigns: this.signMetrics.failedSigns,
-      successRate: this.signMetrics.totalSigns > 0
-        ? this.signMetrics.successfulSigns / this.signMetrics.totalSigns
-        : 0,
-      averageSignTime: avgTime
-    };
+      successRate: this.signMetrics.totalSigns > 0 ? this.signMetrics.successfulSigns / this.signMetrics.totalSigns : 0,
+      averageSignTime: avgTime,
+    }
   }
 
   /**
@@ -342,8 +315,8 @@ export class AsterSigner {
       totalSigns: 0,
       successfulSigns: 0,
       failedSigns: 0,
-      totalTime: 0
-    };
+      totalTime: 0,
+    }
   }
 
   // ============================================================================
@@ -358,7 +331,7 @@ export class AsterSigner {
       credentials.type === 'aster' &&
       typeof credentials.privateKey === 'string' &&
       /^0x[0-9a-fA-F]{64}$/.test(credentials.privateKey)
-    );
+    )
   }
 
   /**
@@ -367,32 +340,28 @@ export class AsterSigner {
   private async deriveAddress(privateKey: string): Promise<string> {
     try {
       // Remove 0x prefix if present
-      const cleanPrivateKey = privateKey.replace(/^0x/, '');
-      const privateKeyBytes = Buffer.from(cleanPrivateKey, 'hex');
+      const cleanPrivateKey = privateKey.replace(/^0x/, '')
+      const privateKeyBytes = Buffer.from(cleanPrivateKey, 'hex')
 
       // Get public key from private key
-      const publicKey = await secp256k1.getPublicKey(privateKeyBytes, false); // Uncompressed
-      const publicKeyBytes = publicKey.slice(1); // Remove 0x04 prefix
+      const publicKey = await secp256k1.getPublicKey(privateKeyBytes, false) // Uncompressed
+      const publicKeyBytes = publicKey.slice(1) // Remove 0x04 prefix
 
       // Hash public key with Keccak256 and take last 20 bytes
-      const addressBytes = this.keccak256Hash(publicKeyBytes).slice(-40);
-      return `0x${addressBytes}`;
-
+      const addressBytes = this.keccak256Hash(publicKeyBytes).slice(-40)
+      return `0x${addressBytes}`
     } catch (error) {
       throw new CredentialManagerError(
         `Failed to derive address from private key: ${error.message}`,
-        ErrorType.VALIDATION_ERROR
-      );
+        ErrorType.VALIDATION_ERROR,
+      )
     }
   }
 
   /**
    * Prepare transaction with default values
    */
-  private prepareTransaction(
-    transaction: AsterTransaction,
-    options?: AsterSignOptions
-  ): AsterTransaction {
+  private prepareTransaction(transaction: AsterTransaction, options?: AsterSignOptions): AsterTransaction {
     return {
       to: transaction.to,
       value: transaction.value || '0',
@@ -400,8 +369,8 @@ export class AsterSigner {
       gasLimit: options?.gasLimit || transaction.gasLimit || '21000',
       gasPrice: options?.gasPrice || transaction.gasPrice || '20000000000', // 20 Gwei
       nonce: options?.nonce ?? transaction.nonce ?? 0,
-      chainId: options?.chainId || transaction.chainId || ASTER_CONSTANTS.MAINNET_CHAIN_ID
-    };
+      chainId: options?.chainId || transaction.chainId || ASTER_CONSTANTS.MAINNET_CHAIN_ID,
+    }
   }
 
   /**
@@ -416,15 +385,15 @@ export class AsterSigner {
       gasLimit: tx.gasLimit,
       gasPrice: tx.gasPrice,
       nonce: tx.nonce,
-      chainId: tx.chainId
-    });
+      chainId: tx.chainId,
+    })
   }
 
   /**
    * Format message according to EIP-191
    */
   private formatEip191Message(message: string): string {
-    return `\x19Ethereum Signed Message:\n${message.length}${message}`;
+    return `\x19Ethereum Signed Message:\n${message.length}${message}`
   }
 
   /**
@@ -432,9 +401,9 @@ export class AsterSigner {
    */
   private keccak256Hash(data: string | Uint8Array): string {
     if (typeof data === 'string') {
-      return keccak256(data);
+      return keccak256(data)
     }
-    return keccak256(data);
+    return keccak256(data)
   }
 
   /**
@@ -442,65 +411,56 @@ export class AsterSigner {
    */
   private async signHash(hash: string, privateKey: string): Promise<string> {
     try {
-      const cleanPrivateKey = privateKey.replace(/^0x/, '');
-      const privateKeyBytes = Buffer.from(cleanPrivateKey, 'hex');
-      const hashBytes = Buffer.from(hash, 'hex');
+      const cleanPrivateKey = privateKey.replace(/^0x/, '')
+      const privateKeyBytes = Buffer.from(cleanPrivateKey, 'hex')
+      const hashBytes = Buffer.from(hash, 'hex')
 
-      const signature = await secp256k1.sign(hashBytes, privateKeyBytes);
+      const signature = await secp256k1.sign(hashBytes, privateKeyBytes)
 
       // Format as 0x-prefixed hex string with recovery id
-      const r = signature.r.toString(16).padStart(64, '0');
-      const s = signature.s.toString(16).padStart(64, '0');
-      const v = (signature.recovery + 27).toString(16).padStart(2, '0');
-
-      return `0x${r}${s}${v}`;
+      const r = signature.r.toString(16).padStart(64, '0')
+      const s = signature.s.toString(16).padStart(64, '0')
+      const v = (signature.recovery + 27).toString(16).padStart(2, '0')
 
+      return `0x${r}${s}${v}`
     } catch (error) {
-      throw new CredentialManagerError(
-        `Failed to sign hash: ${error.message}`,
-        ErrorType.SIGNATURE_ERROR
-      );
+      throw new CredentialManagerError(`Failed to sign hash: ${error.message}`, ErrorType.SIGNATURE_ERROR)
     }
   }
 
   /**
    * Verify ECDSA signature
    */
-  private async verifyEcdsaSignature(
-    hash: string,
-    signature: string,
-    expectedAddress: string
-  ): Promise<boolean> {
+  private async verifyEcdsaSignature(hash: string, signature: string, expectedAddress: string): Promise<boolean> {
     try {
       // Extract r, s, v from signature
-      const sig = signature.replace(/^0x/, '');
+      const sig = signature.replace(/^0x/, '')
       if (sig.length !== 130) {
-        return false;
+        return false
       }
 
-      const r = sig.slice(0, 64);
-      const s = sig.slice(64, 128);
-      const v = parseInt(sig.slice(128, 130), 16);
+      const r = sig.slice(0, 64)
+      const s = sig.slice(64, 128)
+      const v = parseInt(sig.slice(128, 130), 16)
 
       // Recover public key and derive address
-      const recoveryId = v - 27;
-      const hashBytes = Buffer.from(hash, 'hex');
+      const recoveryId = v - 27
+      const hashBytes = Buffer.from(hash, 'hex')
       const signatureBytes = {
         r: Buffer.from(r, 'hex'),
         s: Buffer.from(s, 'hex'),
-        recovery: recoveryId
-      };
-
-      const publicKey = await secp256k1.recover(hashBytes, signatureBytes, recoveryId, false);
-      const publicKeyBytes = publicKey.slice(1); // Remove 0x04 prefix
+        recovery: recoveryId,
+      }
 
-      const addressBytes = this.keccak256Hash(publicKeyBytes).slice(-40);
-      const recoveredAddress = `0x${addressBytes}`;
+      const publicKey = await secp256k1.recover(hashBytes, signatureBytes, recoveryId, false)
+      const publicKeyBytes = publicKey.slice(1) // Remove 0x04 prefix
 
-      return recoveredAddress.toLowerCase() === expectedAddress.toLowerCase();
+      const addressBytes = this.keccak256Hash(publicKeyBytes).slice(-40)
+      const recoveredAddress = `0x${addressBytes}`
 
+      return recoveredAddress.toLowerCase() === expectedAddress.toLowerCase()
     } catch (error) {
-      return false;
+      return false
     }
   }
 }
@@ -558,8 +518,8 @@ export const ASTER_CONSTANTS = {
   /**
    * Default timeout for operations
    */
-  DEFAULT_TIMEOUT: 30000
-} as const;
+  DEFAULT_TIMEOUT: 30000,
+} as const
 
 // ============================================================================
 // Utility Functions
@@ -569,32 +529,32 @@ export const ASTER_CONSTANTS = {
  * Validate Ethereum address format
  */
 export function validateAddressFormat(address: string): boolean {
-  return /^0x[0-9a-fA-F]{40}$/.test(address);
+  return /^0x[0-9a-fA-F]{40}$/.test(address)
 }
 
 /**
  * Validate private key format
  */
 export function validatePrivateKeyFormat(privateKey: string): boolean {
-  return /^0x[0-9a-fA-F]{64}$/.test(privateKey);
+  return /^0x[0-9a-fA-F]{64}$/.test(privateKey)
 }
 
 /**
  * Convert Wei to Ether
  */
 export function weiToEther(wei: string): string {
-  const weiValue = BigInt(wei);
-  const etherValue = weiValue / BigInt('1000000000000000000');
-  return etherValue.toString();
+  const weiValue = BigInt(wei)
+  const etherValue = weiValue / BigInt('1000000000000000000')
+  return etherValue.toString()
 }
 
 /**
  * Convert Ether to Wei
  */
 export function etherToWei(ether: string): string {
-  const etherValue = parseFloat(ether);
-  const weiValue = BigInt(Math.floor(etherValue * 1e18));
-  return weiValue.toString();
+  const etherValue = parseFloat(ether)
+  const weiValue = BigInt(Math.floor(etherValue * 1e18))
+  return weiValue.toString()
 }
 
 /**
@@ -604,10 +564,10 @@ export function estimateGas(transaction: AsterTransaction): string {
   // Basic gas estimation - in production, use proper gas estimation
   if (transaction.data && transaction.data !== '0x') {
     // Contract interaction
-    return '100000';
+    return '100000'
   } else {
     // Simple transfer
-    return '21000';
+    return '21000'
   }
 }
 
@@ -615,4 +575,4 @@ export function estimateGas(transaction: AsterTransaction): string {
 // Export
 // ============================================================================
 
-export default AsterSigner;
+export default AsterSigner

+ 102 - 117
src/core/credential-manager/signers/BinanceSigner.ts

@@ -5,49 +5,55 @@
  * according to Binance API authentication requirements.
  */
 
-import { createHmac } from 'crypto';
-import { Platform, Credentials, BinanceCredentials } from '../../../types/credential.js';
-import { CredentialManagerError, ErrorType } from '../../../types/credential.js';
+import { createHmac } from 'crypto'
+
+import {
+  Platform,
+  Credentials,
+  BinanceCredentials,
+  CredentialManagerError,
+  ErrorType,
+} from '../../../types/credential.js'
 
 // ============================================================================
 // Types and Interfaces
 // ============================================================================
 
 export interface BinanceSignRequest {
-  accountId: string;
-  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
-  endpoint: string;
-  params?: Record<string, any>;
-  options?: BinanceSignOptions;
+  accountId: string
+  method: 'GET' | 'POST' | 'PUT' | 'DELETE'
+  endpoint: string
+  params?: Record<string, any>
+  options?: BinanceSignOptions
 }
 
 export interface BinanceSignOptions {
-  timeout?: number;
-  includeTimestamp?: boolean;
-  recvWindow?: number;
+  timeout?: number
+  includeTimestamp?: boolean
+  recvWindow?: number
 }
 
 export interface BinanceSignResponse {
-  success: boolean;
-  signature: string;
-  algorithm: 'hmac-sha256';
-  apiKey: string;
-  timestamp: number;
-  queryString: string;
-  error?: string;
+  success: boolean
+  signature: string
+  algorithm: 'hmac-sha256'
+  apiKey: string
+  timestamp: number
+  queryString: string
+  error?: string
 }
 
 export interface BinanceVerifyRequest {
-  message: string;
-  signature: string;
-  secretKey: string;
-  algorithm?: 'hmac-sha256';
+  message: string
+  signature: string
+  secretKey: string
+  algorithm?: 'hmac-sha256'
 }
 
 export interface BinanceVerifyResponse {
-  valid: boolean;
-  algorithm: 'hmac-sha256';
-  timestamp: Date;
+  valid: boolean
+  algorithm: 'hmac-sha256'
+  timestamp: Date
 }
 
 // ============================================================================
@@ -55,15 +61,15 @@ export interface BinanceVerifyResponse {
 // ============================================================================
 
 export class BinanceSigner {
-  readonly platform = Platform.BINANCE;
+  readonly platform = Platform.BINANCE
 
-  private accounts = new Map<string, { credentials: BinanceCredentials }>();
+  private accounts = new Map<string, { credentials: BinanceCredentials }>()
   private signMetrics = {
     totalSigns: 0,
     successfulSigns: 0,
     failedSigns: 0,
-    totalTime: 0
-  };
+    totalTime: 0,
+  }
 
   constructor() {
     // Initialize with empty accounts map
@@ -76,55 +82,52 @@ export class BinanceSigner {
     if (!this.validateCredentials(credentials)) {
       throw new CredentialManagerError(
         `Invalid Binance credentials for account ${accountId}`,
-        ErrorType.VALIDATION_ERROR
-      );
+        ErrorType.VALIDATION_ERROR,
+      )
     }
 
-    this.accounts.set(accountId, { credentials });
+    this.accounts.set(accountId, { credentials })
   }
 
   /**
    * Remove an account
    */
   removeAccount(accountId: string): boolean {
-    return this.accounts.delete(accountId);
+    return this.accounts.delete(accountId)
   }
 
   /**
    * Sign Binance API request with HMAC-SHA256
    */
   async signRequest(request: BinanceSignRequest): Promise<BinanceSignResponse> {
-    const startTime = Date.now();
-    this.signMetrics.totalSigns++;
+    const startTime = Date.now()
+    this.signMetrics.totalSigns++
 
     try {
-      const account = this.accounts.get(request.accountId);
+      const account = this.accounts.get(request.accountId)
       if (!account) {
-        throw new CredentialManagerError(
-          `Account ${request.accountId} not found`,
-          ErrorType.SIGNATURE_ERROR
-        );
+        throw new CredentialManagerError(`Account ${request.accountId} not found`, ErrorType.SIGNATURE_ERROR)
       }
 
-      const { credentials } = account;
-      const timestamp = Date.now();
-      const options = request.options || {};
+      const { credentials } = account
+      const timestamp = Date.now()
+      const options = request.options || {}
 
       // Build query string with parameters
       const allParams = {
         ...request.params,
         ...(options.includeTimestamp !== false && { timestamp }),
-        ...(options.recvWindow && { recvWindow: options.recvWindow })
-      };
+        ...(options.recvWindow && { recvWindow: options.recvWindow }),
+      }
 
-      const queryString = this.buildQueryString(allParams);
+      const queryString = this.buildQueryString(allParams)
 
       // Generate HMAC-SHA256 signature
-      const signature = this.computeHmacSha256(queryString, credentials.secretKey);
+      const signature = this.computeHmacSha256(queryString, credentials.secretKey)
 
-      const duration = Date.now() - startTime;
-      this.signMetrics.successfulSigns++;
-      this.signMetrics.totalTime += duration;
+      const duration = Date.now() - startTime
+      this.signMetrics.successfulSigns++
+      this.signMetrics.totalTime += duration
 
       return {
         success: true,
@@ -132,13 +135,12 @@ export class BinanceSigner {
         algorithm: 'hmac-sha256',
         apiKey: credentials.apiKey,
         timestamp,
-        queryString
-      };
-
+        queryString,
+      }
     } catch (error) {
-      const duration = Date.now() - startTime;
-      this.signMetrics.failedSigns++;
-      this.signMetrics.totalTime += duration;
+      const duration = Date.now() - startTime
+      this.signMetrics.failedSigns++
+      this.signMetrics.totalTime += duration
 
       return {
         success: false,
@@ -147,8 +149,8 @@ export class BinanceSigner {
         apiKey: '',
         timestamp: Date.now(),
         queryString: '',
-        error: error instanceof Error ? error.message : 'Unknown signing error'
-      };
+        error: error instanceof Error ? error.message : 'Unknown signing error',
+      }
     }
   }
 
@@ -157,20 +159,20 @@ export class BinanceSigner {
    */
   async verifySignature(request: BinanceVerifyRequest): Promise<BinanceVerifyResponse> {
     try {
-      const expected = this.computeHmacSha256(request.message, request.secretKey);
-      const valid = this.safeStringCompare(expected, request.signature);
+      const expected = this.computeHmacSha256(request.message, request.secretKey)
+      const valid = this.safeStringCompare(expected, request.signature)
 
       return {
         valid,
         algorithm: 'hmac-sha256',
-        timestamp: new Date()
-      };
+        timestamp: new Date(),
+      }
     } catch (error) {
       return {
         valid: false,
         algorithm: 'hmac-sha256',
-        timestamp: new Date()
-      };
+        timestamp: new Date(),
+      }
     }
   }
 
@@ -178,15 +180,12 @@ export class BinanceSigner {
    * Get API key for account
    */
   async getApiKey(accountId: string): Promise<string> {
-    const account = this.accounts.get(accountId);
+    const account = this.accounts.get(accountId)
     if (!account) {
-      throw new CredentialManagerError(
-        `Account ${accountId} not found`,
-        ErrorType.SIGNATURE_ERROR
-      );
+      throw new CredentialManagerError(`Account ${accountId} not found`, ErrorType.SIGNATURE_ERROR)
     }
 
-    return account.credentials.apiKey;
+    return account.credentials.apiKey
   }
 
   /**
@@ -194,27 +193,23 @@ export class BinanceSigner {
    */
   async signBatch(requests: BinanceSignRequest[]): Promise<BinanceSignResponse[]> {
     // Process requests in parallel for better performance
-    const promises = requests.map(request => this.signRequest(request));
-    return Promise.all(promises);
+    const promises = requests.map(request => this.signRequest(request))
+    return Promise.all(promises)
   }
 
   /**
    * Get signing metrics for monitoring
    */
   getMetrics() {
-    const avgTime = this.signMetrics.totalSigns > 0
-      ? this.signMetrics.totalTime / this.signMetrics.totalSigns
-      : 0;
+    const avgTime = this.signMetrics.totalSigns > 0 ? this.signMetrics.totalTime / this.signMetrics.totalSigns : 0
 
     return {
       totalSigns: this.signMetrics.totalSigns,
       successfulSigns: this.signMetrics.successfulSigns,
       failedSigns: this.signMetrics.failedSigns,
-      successRate: this.signMetrics.totalSigns > 0
-        ? this.signMetrics.successfulSigns / this.signMetrics.totalSigns
-        : 0,
-      averageSignTime: avgTime
-    };
+      successRate: this.signMetrics.totalSigns > 0 ? this.signMetrics.successfulSigns / this.signMetrics.totalSigns : 0,
+      averageSignTime: avgTime,
+    }
   }
 
   /**
@@ -225,8 +220,8 @@ export class BinanceSigner {
       totalSigns: 0,
       successfulSigns: 0,
       failedSigns: 0,
-      totalTime: 0
-    };
+      totalTime: 0,
+    }
   }
 
   // ============================================================================
@@ -243,26 +238,22 @@ export class BinanceSigner {
       credentials.apiKey.length > 0 &&
       typeof credentials.secretKey === 'string' &&
       credentials.secretKey.length > 0
-    );
+    )
   }
 
   /**
    * Build query string from parameters (sorted by key)
    */
   private buildQueryString(params: Record<string, any>): string {
-    const sortedKeys = Object.keys(params).sort();
-    return sortedKeys
-      .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
-      .join('&');
+    const sortedKeys = Object.keys(params).sort()
+    return sortedKeys.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`).join('&')
   }
 
   /**
    * Compute HMAC-SHA256 signature
    */
   private computeHmacSha256(message: string, secret: string): string {
-    return createHmac('sha256', secret)
-      .update(message)
-      .digest('hex');
+    return createHmac('sha256', secret).update(message).digest('hex')
   }
 
   /**
@@ -270,15 +261,15 @@ export class BinanceSigner {
    */
   private safeStringCompare(a: string, b: string): boolean {
     if (a.length !== b.length) {
-      return false;
+      return false
     }
 
-    let result = 0;
+    let result = 0
     for (let i = 0; i < a.length; i++) {
-      result |= a.charCodeAt(i) ^ b.charCodeAt(i);
+      result |= a.charCodeAt(i) ^ b.charCodeAt(i)
     }
 
-    return result === 0;
+    return result === 0
   }
 }
 
@@ -318,7 +309,7 @@ export const BINANCE_CONSTANTS = {
     '/api/v3/myTrades',
     '/fapi/v1/account',
     '/fapi/v1/balance',
-    '/fapi/v1/positionRisk'
+    '/fapi/v1/positionRisk',
   ],
 
   /**
@@ -331,9 +322,9 @@ export const BINANCE_CONSTANTS = {
     '/api/v3/depth',
     '/api/v3/trades',
     '/api/v3/ticker/price',
-    '/api/v3/ticker/24hr'
-  ]
-} as const;
+    '/api/v3/ticker/24hr',
+  ],
+} as const
 
 // ============================================================================
 // Utility Functions
@@ -343,9 +334,7 @@ export const BINANCE_CONSTANTS = {
  * Check if endpoint requires signature
  */
 export function requiresSignature(endpoint: string): boolean {
-  return BINANCE_CONSTANTS.SIGNED_ENDPOINTS.some(pattern =>
-    endpoint.startsWith(pattern)
-  );
+  return BINANCE_CONSTANTS.SIGNED_ENDPOINTS.some(pattern => endpoint.startsWith(pattern))
 }
 
 /**
@@ -353,7 +342,7 @@ export function requiresSignature(endpoint: string): boolean {
  */
 export function validateApiKeyFormat(apiKey: string): boolean {
   // Binance API keys are typically 64 characters long, alphanumeric
-  return /^[A-Za-z0-9]{64}$/.test(apiKey);
+  return /^[A-Za-z0-9]{64}$/.test(apiKey)
 }
 
 /**
@@ -361,44 +350,40 @@ export function validateApiKeyFormat(apiKey: string): boolean {
  */
 export function validateSecretKeyFormat(secretKey: string): boolean {
   // Binance secret keys are typically 64 characters long, alphanumeric
-  return /^[A-Za-z0-9]{64}$/.test(secretKey);
+  return /^[A-Za-z0-9]{64}$/.test(secretKey)
 }
 
 /**
  * Build complete request URL with query parameters
  */
-export function buildRequestUrl(
-  baseUrl: string,
-  endpoint: string,
-  queryString: string
-): string {
-  const separator = queryString ? '?' : '';
-  return `${baseUrl}${endpoint}${separator}${queryString}`;
+export function buildRequestUrl(baseUrl: string, endpoint: string, queryString: string): string {
+  const separator = queryString ? '?' : ''
+  return `${baseUrl}${endpoint}${separator}${queryString}`
 }
 
 /**
  * Extract parameters from query string
  */
 export function parseQueryString(queryString: string): Record<string, string> {
-  const params: Record<string, string> = {};
+  const params: Record<string, string> = {}
 
   if (!queryString) {
-    return params;
+    return params
   }
 
-  const pairs = queryString.split('&');
+  const pairs = queryString.split('&')
   for (const pair of pairs) {
-    const [key, value] = pair.split('=');
+    const [key, value] = pair.split('=')
     if (key && value) {
-      params[decodeURIComponent(key)] = decodeURIComponent(value);
+      params[decodeURIComponent(key)] = decodeURIComponent(value)
     }
   }
 
-  return params;
+  return params
 }
 
 // ============================================================================
 // Export
 // ============================================================================
 
-export default BinanceSigner;
+export default BinanceSigner

+ 166 - 173
src/core/credential-manager/signers/PacificaSigner.ts

@@ -5,67 +5,67 @@
  * Provides high-performance signing and verification with batch support.
  */
 
-import * as nacl from 'tweetnacl';
+import * as nacl from 'tweetnacl'
+
 import {
   Platform,
   ISignerStrategy,
   Credentials,
   Ed25519Credentials,
-  SignResult,
   CredentialErrorCode,
-  CredentialManagerError
-} from '@/types/credential';
+  CredentialManagerError,
+} from '@/types/credential'
 
 /**
  * Pacifica-specific interfaces matching contract specifications
  */
 export interface PacificaOrderType {
-  MARKET: 'market';
-  LIMIT: 'limit';
-  STOP_LOSS: 'stop_loss';
-  TAKE_PROFIT: 'take_profit';
-  CANCEL: 'cancel';
-  CANCEL_ALL: 'cancel_all';
+  MARKET: 'market'
+  LIMIT: 'limit'
+  STOP_LOSS: 'stop_loss'
+  TAKE_PROFIT: 'take_profit'
+  CANCEL: 'cancel'
+  CANCEL_ALL: 'cancel_all'
 }
 
 export interface PacificaSignRequest {
-  accountId: string;
-  message: Uint8Array;
-  orderType: keyof PacificaOrderType;
-  options?: PacificaSignOptions;
+  accountId: string
+  message: Uint8Array
+  orderType: keyof PacificaOrderType
+  options?: PacificaSignOptions
 }
 
 export interface PacificaSignOptions {
-  timeout?: number;
-  includeTimestamp?: boolean;
-  encoding?: 'base64' | 'base58' | 'hex';
-  enableBatchOptimization?: boolean;
+  timeout?: number
+  includeTimestamp?: boolean
+  encoding?: 'base64' | 'base58' | 'hex'
+  enableBatchOptimization?: boolean
 }
 
 export interface PacificaSignResponse {
-  success: boolean;
-  signature?: string;
-  algorithm: 'ed25519';
-  publicKey?: string;
-  orderType?: keyof PacificaOrderType;
-  timestamp: Date;
-  error?: string;
+  success: boolean
+  signature?: string
+  algorithm: 'ed25519'
+  publicKey?: string
+  orderType?: keyof PacificaOrderType
+  timestamp: Date
+  error?: string
 }
 
 export interface PacificaVerifyRequest {
-  accountId: string;
-  message: Uint8Array;
-  signature: string;
-  publicKey: string;
-  orderType?: keyof PacificaOrderType;
+  accountId: string
+  message: Uint8Array
+  signature: string
+  publicKey: string
+  orderType?: keyof PacificaOrderType
 }
 
 export interface PacificaVerifyResponse {
-  isValid: boolean;
-  algorithm: 'ed25519';
-  publicKey: string;
-  timestamp: Date;
-  error?: string;
+  isValid: boolean
+  algorithm: 'ed25519'
+  publicKey: string
+  timestamp: Date
+  error?: string
 }
 
 /**
@@ -80,8 +80,8 @@ export const PACIFICA_CONSTANTS = {
   SIGNATURE_BASE64_LENGTH: 88,
   MAX_MESSAGE_SIZE: 1024 * 1024, // 1MB
   DEFAULT_SIGN_TIMEOUT: 30000,
-  MAX_BATCH_SIZE: 100
-};
+  MAX_BATCH_SIZE: 100,
+}
 
 /**
  * Utility functions for Pacifica operations
@@ -91,15 +91,15 @@ export class PacificaKeyUtils {
    * Convert hex string to Uint8Array
    */
   static hexToBytes(hex: string): Uint8Array {
-    const clean = hex.replace(/^0x/, '').toLowerCase();
+    const clean = hex.replace(/^0x/, '').toLowerCase()
     if (clean.length !== 64) {
-      throw new Error('Invalid hex length for Ed25519 private key');
+      throw new Error('Invalid hex length for Ed25519 private key')
     }
-    const bytes = new Uint8Array(32);
+    const bytes = new Uint8Array(32)
     for (let i = 0; i < 32; i++) {
-      bytes[i] = parseInt(clean.substr(i * 2, 2), 16);
+      bytes[i] = parseInt(clean.substr(i * 2, 2), 16)
     }
-    return bytes;
+    return bytes
   }
 
   /**
@@ -108,55 +108,55 @@ export class PacificaKeyUtils {
   static bytesToHex(bytes: Uint8Array): string {
     return Array.from(bytes)
       .map(b => b.toString(16).padStart(2, '0'))
-      .join('');
+      .join('')
   }
 
   /**
    * Convert Uint8Array to base64 string
    */
   static bytesToBase64(bytes: Uint8Array): string {
-    return Buffer.from(bytes).toString('base64');
+    return Buffer.from(bytes).toString('base64')
   }
 
   /**
    * Convert base64 string to Uint8Array
    */
   static base64ToBytes(base64: string): Uint8Array {
-    return new Uint8Array(Buffer.from(base64, 'base64'));
+    return new Uint8Array(Buffer.from(base64, 'base64'))
   }
 
   /**
    * Simple base58 encoding (for public keys)
    */
   static bytesToBase58(bytes: Uint8Array): string {
-    const alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
-    let num = BigInt('0x' + this.bytesToHex(bytes));
-    let result = '';
+    const alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
+    let num = BigInt('0x' + this.bytesToHex(bytes))
+    let result = ''
 
     while (num > 0) {
-      result = alphabet[Number(num % BigInt(58))] + result;
-      num = num / BigInt(58);
+      result = alphabet[Number(num % BigInt(58))] + result
+      num = num / BigInt(58)
     }
 
     // Handle leading zeros
     for (const byte of bytes) {
       if (byte === 0) {
-        result = '1' + result;
+        result = '1' + result
       } else {
-        break;
+        break
       }
     }
 
-    return result;
+    return result
   }
 
   /**
    * Derive public key from private key
    */
   static derivePublicKey(privateKeyHex: string): string {
-    const privateKeyBytes = this.hexToBytes(privateKeyHex);
-    const keyPair = nacl.sign.keyPair.fromSeed(privateKeyBytes);
-    return this.bytesToBase58(keyPair.publicKey);
+    const privateKeyBytes = this.hexToBytes(privateKeyHex)
+    const keyPair = nacl.sign.keyPair.fromSeed(privateKeyBytes)
+    return this.bytesToBase58(keyPair.publicKey)
   }
 
   /**
@@ -164,10 +164,10 @@ export class PacificaKeyUtils {
    */
   static validatePrivateKey(privateKeyHex: string): boolean {
     try {
-      const clean = privateKeyHex.replace(/^0x/, '').toLowerCase();
-      return /^[0-9a-f]{64}$/.test(clean);
+      const clean = privateKeyHex.replace(/^0x/, '').toLowerCase()
+      return /^[0-9a-f]{64}$/.test(clean)
     } catch {
-      return false;
+      return false
     }
   }
 
@@ -176,9 +176,9 @@ export class PacificaKeyUtils {
    */
   static validatePublicKey(publicKeyBase58: string): boolean {
     try {
-      return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(publicKeyBase58);
+      return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(publicKeyBase58)
     } catch {
-      return false;
+      return false
     }
   }
 }
@@ -187,55 +187,55 @@ export class PacificaKeyUtils {
  * Performance metrics for Pacifica signer
  */
 export class PacificaSignerMetrics {
-  totalSignatures = 0;
-  successfulSignatures = 0;
-  failedSignatures = 0;
-  averageSignTime = 0;
-  maxSignTime = 0;
-  minSignTime = Infinity;
-  batchSignatures = 0;
-  averageBatchSize = 0;
-  lastResetAt = new Date();
-
-  private signTimes: number[] = [];
+  totalSignatures = 0
+  successfulSignatures = 0
+  failedSignatures = 0
+  averageSignTime = 0
+  maxSignTime = 0
+  minSignTime = Infinity
+  batchSignatures = 0
+  averageBatchSize = 0
+  lastResetAt = new Date()
+
+  private signTimes: number[] = []
 
   recordSignature(success: boolean, duration: number, batchSize = 1): void {
-    this.totalSignatures++;
+    this.totalSignatures++
 
     if (success) {
-      this.successfulSignatures++;
+      this.successfulSignatures++
     } else {
-      this.failedSignatures++;
+      this.failedSignatures++
     }
 
-    this.signTimes.push(duration);
-    this.maxSignTime = Math.max(this.maxSignTime, duration);
-    this.minSignTime = Math.min(this.minSignTime, duration);
+    this.signTimes.push(duration)
+    this.maxSignTime = Math.max(this.maxSignTime, duration)
+    this.minSignTime = Math.min(this.minSignTime, duration)
 
     // Calculate rolling average
     if (this.signTimes.length > 100) {
-      this.signTimes = this.signTimes.slice(-100);
+      this.signTimes = this.signTimes.slice(-100)
     }
 
-    this.averageSignTime = this.signTimes.reduce((a, b) => a + b, 0) / this.signTimes.length;
+    this.averageSignTime = this.signTimes.reduce((a, b) => a + b, 0) / this.signTimes.length
 
     if (batchSize > 1) {
-      this.batchSignatures++;
-      this.averageBatchSize = ((this.averageBatchSize * (this.batchSignatures - 1)) + batchSize) / this.batchSignatures;
+      this.batchSignatures++
+      this.averageBatchSize = (this.averageBatchSize * (this.batchSignatures - 1) + batchSize) / this.batchSignatures
     }
   }
 
   reset(): void {
-    this.totalSignatures = 0;
-    this.successfulSignatures = 0;
-    this.failedSignatures = 0;
-    this.averageSignTime = 0;
-    this.maxSignTime = 0;
-    this.minSignTime = Infinity;
-    this.batchSignatures = 0;
-    this.averageBatchSize = 0;
-    this.signTimes = [];
-    this.lastResetAt = new Date();
+    this.totalSignatures = 0
+    this.successfulSignatures = 0
+    this.failedSignatures = 0
+    this.averageSignTime = 0
+    this.maxSignTime = 0
+    this.minSignTime = Infinity
+    this.batchSignatures = 0
+    this.averageBatchSize = 0
+    this.signTimes = []
+    this.lastResetAt = new Date()
   }
 
   getReport() {
@@ -249,8 +249,8 @@ export class PacificaSignerMetrics {
       minSignTime: this.minSignTime === Infinity ? 0 : this.minSignTime,
       batchSignatures: this.batchSignatures,
       averageBatchSize: this.averageBatchSize,
-      lastResetAt: this.lastResetAt
-    };
+      lastResetAt: this.lastResetAt,
+    }
   }
 }
 
@@ -258,70 +258,66 @@ export class PacificaSignerMetrics {
  * Pacifica signer strategy implementation
  */
 export class PacificaSigner implements ISignerStrategy {
-  readonly platform = Platform.PACIFICA;
-  private metrics = new PacificaSignerMetrics();
+  readonly platform = Platform.PACIFICA
+  private metrics = new PacificaSignerMetrics()
 
   /**
    * Sign message using Ed25519
    */
   async sign(message: Uint8Array, credentials: Credentials): Promise<string> {
-    const startTime = Date.now();
+    const startTime = Date.now()
 
     try {
       // Validate credentials
       if (!this.isEd25519Credentials(credentials)) {
         throw new CredentialManagerError(
           CredentialErrorCode.ACCOUNT_INVALID_CREDENTIALS,
-          'Invalid credentials for Pacifica signer'
-        );
+          'Invalid credentials for Pacifica signer',
+        )
       }
 
       // Validate message size
       if (message.length > PACIFICA_CONSTANTS.MAX_MESSAGE_SIZE) {
         throw new CredentialManagerError(
           CredentialErrorCode.MESSAGE_TOO_LARGE,
-          `Message too large: ${message.length} bytes (max: ${PACIFICA_CONSTANTS.MAX_MESSAGE_SIZE})`
-        );
+          `Message too large: ${message.length} bytes (max: ${PACIFICA_CONSTANTS.MAX_MESSAGE_SIZE})`,
+        )
       }
 
       // Validate private key
       if (!PacificaKeyUtils.validatePrivateKey(credentials.privateKey)) {
-        throw new CredentialManagerError(
-          CredentialErrorCode.ACCOUNT_INVALID_CREDENTIALS,
-          'Invalid private key format'
-        );
+        throw new CredentialManagerError(CredentialErrorCode.ACCOUNT_INVALID_CREDENTIALS, 'Invalid private key format')
       }
 
       // Convert private key to bytes
-      const privateKeyBytes = PacificaKeyUtils.hexToBytes(credentials.privateKey);
+      const privateKeyBytes = PacificaKeyUtils.hexToBytes(credentials.privateKey)
 
       // Create key pair
-      const keyPair = nacl.sign.keyPair.fromSeed(privateKeyBytes);
+      const keyPair = nacl.sign.keyPair.fromSeed(privateKeyBytes)
 
       // Sign message
-      const signature = nacl.sign.detached(message, keyPair.secretKey);
+      const signature = nacl.sign.detached(message, keyPair.secretKey)
 
       // Convert to base64
-      const signatureBase64 = PacificaKeyUtils.bytesToBase64(signature);
+      const signatureBase64 = PacificaKeyUtils.bytesToBase64(signature)
 
-      const duration = Date.now() - startTime;
-      this.metrics.recordSignature(true, duration);
-
-      return signatureBase64;
+      const duration = Date.now() - startTime
+      this.metrics.recordSignature(true, duration)
 
+      return signatureBase64
     } catch (error) {
-      const duration = Date.now() - startTime;
-      this.metrics.recordSignature(false, duration);
+      const duration = Date.now() - startTime
+      this.metrics.recordSignature(false, duration)
 
       if (error instanceof CredentialManagerError) {
-        throw error;
+        throw error
       }
 
       throw new CredentialManagerError(
         CredentialErrorCode.SIGNING_FAILED,
         `Pacifica signing failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
-        error
-      );
+        error,
+      )
     }
   }
 
@@ -332,33 +328,32 @@ export class PacificaSigner implements ISignerStrategy {
     try {
       // Validate inputs
       if (!message || message.length === 0) {
-        return false;
+        return false
       }
 
       if (!signature || typeof signature !== 'string') {
-        return false;
+        return false
       }
 
       if (!publicKey || !PacificaKeyUtils.validatePublicKey(publicKey)) {
-        return false;
+        return false
       }
 
       // Convert signature from base64
-      const signatureBytes = PacificaKeyUtils.base64ToBytes(signature);
+      const signatureBytes = PacificaKeyUtils.base64ToBytes(signature)
 
       if (signatureBytes.length !== PACIFICA_CONSTANTS.SIGNATURE_LENGTH) {
-        return false;
+        return false
       }
 
       // For verification, we need to derive the public key bytes from base58
       // This is a simplified approach - in practice, you'd have proper base58 decoding
-      const publicKeyBytes = new Uint8Array(32); // Placeholder - should decode from base58
+      const publicKeyBytes = new Uint8Array(32) // Placeholder - should decode from base58
 
       // Verify signature
-      return nacl.sign.detached.verify(message, signatureBytes, publicKeyBytes);
-
+      return nacl.sign.detached.verify(message, signatureBytes, publicKeyBytes)
     } catch (error) {
-      return false;
+      return false
     }
   }
 
@@ -366,23 +361,23 @@ export class PacificaSigner implements ISignerStrategy {
    * Pacifica-specific order signing
    */
   async signOrder(request: PacificaSignRequest): Promise<PacificaSignResponse> {
-    const startTime = Date.now();
+    const startTime = Date.now()
 
     try {
       // Validate request
       if (!request.message || request.message.length === 0) {
-        throw new Error('Message is required');
+        throw new Error('Message is required')
       }
 
       // Apply timeout if specified
-      const timeout = request.options?.timeout || PACIFICA_CONSTANTS.DEFAULT_SIGN_TIMEOUT;
-      const signPromise = this.signMessage(request.message, request.accountId);
+      const timeout = request.options?.timeout || PACIFICA_CONSTANTS.DEFAULT_SIGN_TIMEOUT
+      const signPromise = this.signMessage(request.message, request.accountId)
 
       const timeoutPromise = new Promise<never>((_, reject) => {
-        setTimeout(() => reject(new Error('Signing timeout')), timeout);
-      });
+        setTimeout(() => reject(new Error('Signing timeout')), timeout)
+      })
 
-      const result = await Promise.race([signPromise, timeoutPromise]);
+      const result = await Promise.race([signPromise, timeoutPromise])
 
       const response: PacificaSignResponse = {
         success: true,
@@ -390,18 +385,17 @@ export class PacificaSigner implements ISignerStrategy {
         algorithm: 'ed25519',
         publicKey: result.publicKey,
         orderType: request.orderType,
-        timestamp: new Date()
-      };
-
-      return response;
+        timestamp: new Date(),
+      }
 
+      return response
     } catch (error) {
       return {
         success: false,
         algorithm: 'ed25519',
         timestamp: new Date(),
-        error: error instanceof Error ? error.message : 'Unknown error'
-      };
+        error: error instanceof Error ? error.message : 'Unknown error',
+      }
     }
   }
 
@@ -410,23 +404,22 @@ export class PacificaSigner implements ISignerStrategy {
    */
   async verifySignature(request: PacificaVerifyRequest): Promise<PacificaVerifyResponse> {
     try {
-      const isValid = await this.verify(request.message, request.signature, request.publicKey);
+      const isValid = await this.verify(request.message, request.signature, request.publicKey)
 
       return {
         isValid,
         algorithm: 'ed25519',
         publicKey: request.publicKey,
-        timestamp: new Date()
-      };
-
+        timestamp: new Date(),
+      }
     } catch (error) {
       return {
         isValid: false,
         algorithm: 'ed25519',
         publicKey: request.publicKey,
         timestamp: new Date(),
-        error: error instanceof Error ? error.message : 'Unknown error'
-      };
+        error: error instanceof Error ? error.message : 'Unknown error',
+      }
     }
   }
 
@@ -438,49 +431,46 @@ export class PacificaSigner implements ISignerStrategy {
     // For now, throw an error indicating this needs account management
     throw new CredentialManagerError(
       CredentialErrorCode.ACCOUNT_NOT_FOUND,
-      `Cannot get public key for account ${accountId} - account management not available`
-    );
+      `Cannot get public key for account ${accountId} - account management not available`,
+    )
   }
 
   /**
    * Batch signing for better performance
    */
   async signBatch(requests: PacificaSignRequest[]): Promise<PacificaSignResponse[]> {
-    const startTime = Date.now();
+    const startTime = Date.now()
 
     try {
       // Validate batch size
       if (requests.length > PACIFICA_CONSTANTS.MAX_BATCH_SIZE) {
         throw new CredentialManagerError(
           CredentialErrorCode.SIGNING_FAILED,
-          `Batch size ${requests.length} exceeds maximum ${PACIFICA_CONSTANTS.MAX_BATCH_SIZE}`
-        );
+          `Batch size ${requests.length} exceeds maximum ${PACIFICA_CONSTANTS.MAX_BATCH_SIZE}`,
+        )
       }
 
       // Process all requests
-      const results = await Promise.all(
-        requests.map(request => this.signOrder(request))
-      );
-
-      const duration = Date.now() - startTime;
-      const successCount = results.filter(r => r.success).length;
-      this.metrics.recordSignature(successCount === requests.length, duration, requests.length);
+      const results = await Promise.all(requests.map(request => this.signOrder(request)))
 
-      return results;
+      const duration = Date.now() - startTime
+      const successCount = results.filter(r => r.success).length
+      this.metrics.recordSignature(successCount === requests.length, duration, requests.length)
 
+      return results
     } catch (error) {
-      const duration = Date.now() - startTime;
-      this.metrics.recordSignature(false, duration, requests.length);
+      const duration = Date.now() - startTime
+      this.metrics.recordSignature(false, duration, requests.length)
 
       // Return error response for all requests
       const errorResponse: PacificaSignResponse = {
         success: false,
         algorithm: 'ed25519',
         timestamp: new Date(),
-        error: error instanceof Error ? error.message : 'Batch signing failed'
-      };
+        error: error instanceof Error ? error.message : 'Batch signing failed',
+      }
 
-      return requests.map(() => ({ ...errorResponse }));
+      return requests.map(() => ({ ...errorResponse }))
     }
   }
 
@@ -488,22 +478,25 @@ export class PacificaSigner implements ISignerStrategy {
    * Get performance metrics
    */
   getMetrics() {
-    return this.metrics.getReport();
+    return this.metrics.getReport()
   }
 
   /**
    * Reset performance metrics
    */
   resetMetrics(): void {
-    this.metrics.reset();
+    this.metrics.reset()
   }
 
   /**
    * Helper method to sign a message (internal use)
    */
-  private async signMessage(message: Uint8Array, accountId: string): Promise<{
-    signature: string;
-    publicKey: string;
+  private async signMessage(
+    message: Uint8Array,
+    accountId: string,
+  ): Promise<{
+    signature: string
+    publicKey: string
   }> {
     // This is a placeholder - in practice, this would:
     // 1. Look up the account by ID
@@ -513,14 +506,14 @@ export class PacificaSigner implements ISignerStrategy {
 
     throw new CredentialManagerError(
       CredentialErrorCode.ACCOUNT_NOT_FOUND,
-      `Cannot sign for account ${accountId} - account management not available`
-    );
+      `Cannot sign for account ${accountId} - account management not available`,
+    )
   }
 
   /**
    * Type guard for Ed25519 credentials
    */
   private isEd25519Credentials(credentials: Credentials): credentials is Ed25519Credentials {
-    return credentials.type === 'ed25519' && 'privateKey' in credentials;
+    return credentials.type === 'ed25519' && 'privateKey' in credentials
   }
-}
+}

+ 2 - 2
src/examples/http_client_integration_demo.ts

@@ -6,14 +6,14 @@
  * 演示新的统一HTTP客户端架构功能
  */
 
+import type { HttpClientRequest, HttpClientResponse } from '@/types/httpClient'
+import type { PlatformConfig } from '@/types/platformAdapter'
 import {
   createUniversalHttpClient,
   HttpClientAdapter,
   httpClientAdapter,
   pacificaApiCall,
 } from '@/utils/universalHttpClient'
-import type { HttpClientRequest, HttpClientResponse } from '@/types/httpClient'
-import type { PlatformConfig } from '@/types/platformAdapter'
 
 /**
  * 基础功能演示

+ 141 - 139
src/types/credential.ts

@@ -15,7 +15,7 @@
 export enum Platform {
   PACIFICA = 'pacifica',
   ASTER = 'aster',
-  BINANCE = 'binance'
+  BINANCE = 'binance',
 }
 
 /**
@@ -24,7 +24,7 @@ export enum Platform {
 export enum SignatureType {
   ED25519 = 'ed25519',
   EIP191 = 'eip191',
-  HMAC_SHA256 = 'hmac-sha256'
+  HMAC_SHA256 = 'hmac-sha256',
 }
 
 // ============================================================================
@@ -35,63 +35,69 @@ export enum SignatureType {
  * Base credentials interface
  */
 export interface BaseCredentials {
-  type: string;
+  type: string
 }
 
 /**
  * Ed25519 credentials for Pacifica platform
  */
 export interface Ed25519Credentials extends BaseCredentials {
-  type: 'ed25519';
-  privateKey: string; // 64-character hex string
+  type: 'ed25519'
+  privateKey: string // 64-character hex string
 }
 
 /**
  * Pacifica credentials (alias for Ed25519)
  */
 export interface PacificaCredentials extends BaseCredentials {
-  type: 'pacifica';
-  privateKey: string; // 64-character hex string
+  type: 'pacifica'
+  privateKey: string // 64-character hex string
 }
 
 /**
  * EIP-191 credentials for Aster platform
  */
 export interface Eip191Credentials extends BaseCredentials {
-  type: 'eip191';
-  privateKey: string; // 0x-prefixed hex string
+  type: 'eip191'
+  privateKey: string // 0x-prefixed hex string
 }
 
 /**
  * Aster credentials (alias for EIP-191)
  */
 export interface AsterCredentials extends BaseCredentials {
-  type: 'aster';
-  privateKey: string; // 0x-prefixed hex string
+  type: 'aster'
+  privateKey: string // 0x-prefixed hex string
 }
 
 /**
  * HMAC credentials for Binance platform
  */
 export interface HmacCredentials extends BaseCredentials {
-  type: 'hmac';
-  apiKey: string;
-  secretKey: string;
+  type: 'hmac'
+  apiKey: string
+  secretKey: string
 }
 
 /**
  * Binance credentials (alias for HMAC)
  */
 export interface BinanceCredentials extends BaseCredentials {
-  type: 'binance';
-  apiKey: string;
-  secretKey: string;
+  type: 'binance'
+  apiKey: string
+  secretKey: string
 }
 
 /**
  * Union type for all credential types
  */
-export type Credentials = Ed25519Credentials | PacificaCredentials | Eip191Credentials | AsterCredentials | HmacCredentials | BinanceCredentials;
+export type Credentials =
+  | Ed25519Credentials
+  | PacificaCredentials
+  | Eip191Credentials
+  | AsterCredentials
+  | HmacCredentials
+  | BinanceCredentials
 
 // ============================================================================
 // Account Interface Definition (T015)
@@ -101,26 +107,26 @@ export type Credentials = Ed25519Credentials | PacificaCredentials | Eip191Crede
  * Account configuration from config file
  */
 export interface AccountConfig {
-  id: string;
-  platform: Platform;
-  name: string;
-  credentials: Credentials;
-  enabled?: boolean;
-  metadata?: Record<string, any>;
+  id: string
+  platform: Platform
+  name: string
+  credentials: Credentials
+  enabled?: boolean
+  metadata?: Record<string, any>
 }
 
 /**
  * Runtime account representation
  */
 export interface Account {
-  id: string;
-  platform: Platform;
-  name: string;
-  credentials: Credentials;
-  enabled: boolean;
-  metadata: Record<string, any>;
-  createdAt: Date;
-  lastUsed?: Date;
+  id: string
+  platform: Platform
+  name: string
+  credentials: Credentials
+  enabled: boolean
+  metadata: Record<string, any>
+  createdAt: Date
+  lastUsed?: Date
 }
 
 // ============================================================================
@@ -134,14 +140,14 @@ export interface ISigner {
   /**
    * Platform this signer supports
    */
-  readonly platform: Platform;
+  readonly platform: Platform
 
   /**
    * Register platform signing strategy
    * @param platform Platform type
    * @param strategy Signing strategy
    */
-  registerStrategy(platform: Platform, strategy: ISignerStrategy): void;
+  registerStrategy(platform: Platform, strategy: ISignerStrategy): void
 
   /**
    * Execute signing
@@ -149,7 +155,7 @@ export interface ISigner {
    * @param message Message to sign
    * @returns Signing result
    */
-  sign(accountId: string, message: Uint8Array): Promise<SignResult>;
+  sign(accountId: string, message: Uint8Array): Promise<SignResult>
 
   /**
    * Verify signature
@@ -158,14 +164,14 @@ export interface ISigner {
    * @param signature Signature string
    * @returns Verification result
    */
-  verify(accountId: string, message: Uint8Array, signature: string): Promise<boolean>;
+  verify(accountId: string, message: Uint8Array, signature: string): Promise<boolean>
 }
 
 /**
  * Platform-specific signing strategy interface
  */
 export interface ISignerStrategy {
-  platform: Platform;
+  platform: Platform
 
   /**
    * Execute signing
@@ -173,7 +179,7 @@ export interface ISignerStrategy {
    * @param credentials Account credentials
    * @returns Signature string
    */
-  sign(message: Uint8Array, credentials: Credentials): Promise<string>;
+  sign(message: Uint8Array, credentials: Credentials): Promise<string>
 
   /**
    * Verify signature
@@ -182,7 +188,7 @@ export interface ISignerStrategy {
    * @param publicKey Public key for verification
    * @returns Verification result
    */
-  verify(message: Uint8Array, signature: string, publicKey: string): Promise<boolean>;
+  verify(message: Uint8Array, signature: string, publicKey: string): Promise<boolean>
 }
 
 /**
@@ -192,14 +198,14 @@ export interface IPlatformDetector {
   /**
    * Detection confidence (0-1)
    */
-  confidence: number;
+  confidence: number
 
   /**
    * Detect platform type from credentials
    * @param credentials Credential object
    * @returns Platform type or null if cannot detect
    */
-  detect(credentials: any): Platform | null;
+  detect(credentials: any): Platform | null
 }
 
 // ============================================================================
@@ -215,40 +221,40 @@ export interface IConfigLoader {
    * @param filePath Configuration file path
    * @returns Load result
    */
-  loadConfig(filePath: string): Promise<LoadResult>;
+  loadConfig(filePath: string): Promise<LoadResult>
 
   /**
    * Watch configuration file for changes
    * @param filePath Configuration file path
    * @param callback Change callback function
    */
-  watchConfig(filePath: string, callback: (accounts: Account[]) => void): void;
+  watchConfig(filePath: string, callback: (accounts: Account[]) => void): void
 
   /**
    * Stop watching configuration file
    */
-  stopWatching(): void;
+  stopWatching(): void
 }
 
 /**
  * Configuration file structure
  */
 export interface ConfigFile {
-  version: string;
-  accounts: AccountConfig[];
-  metadata?: Record<string, any>;
+  version: string
+  accounts: AccountConfig[]
+  metadata?: Record<string, any>
 }
 
 /**
  * Configuration load result
  */
 export interface LoadResult {
-  success: boolean;
-  accounts: Account[];
-  errors?: string[];
-  loadTime: number; // milliseconds
-  filePath?: string;
-  version?: string;
+  success: boolean
+  accounts: Account[]
+  errors?: string[]
+  loadTime: number // milliseconds
+  filePath?: string
+  version?: string
 }
 
 // ============================================================================
@@ -259,10 +265,10 @@ export interface LoadResult {
  * Base error interface
  */
 export interface CredentialError {
-  code: string;
-  message: string;
-  details?: any;
-  timestamp: Date;
+  code: string
+  message: string
+  details?: any
+  timestamp: Date
 }
 
 /**
@@ -299,7 +305,7 @@ export enum CredentialErrorCode {
   FILE_PERMISSION_DENIED = 'FILE_PERMISSION_DENIED',
 
   // Additional errors
-  MESSAGE_TOO_LARGE = 'MESSAGE_TOO_LARGE'
+  MESSAGE_TOO_LARGE = 'MESSAGE_TOO_LARGE',
 }
 
 /**
@@ -309,44 +315,40 @@ export enum ErrorType {
   CONFIG_LOAD_ERROR = 'config_load_error',
   VALIDATION_ERROR = 'validation_error',
   SIGNATURE_ERROR = 'signature_error',
-  PLATFORM_DETECTION_ERROR = 'platform_detection_error'
+  PLATFORM_DETECTION_ERROR = 'platform_detection_error',
 }
 
 /**
  * Credential manager specific error
  */
 export class CredentialManagerError extends Error {
-  public readonly type: ErrorType;
+  public readonly type: ErrorType
 
   constructor(
     message: string,
     type: ErrorType,
-    public readonly details?: any
+    public readonly details?: any,
   ) {
-    super(message);
-    this.name = 'CredentialManagerError';
-    this.type = type;
+    super(message)
+    this.name = 'CredentialManagerError'
+    this.type = type
   }
 
   // Legacy constructor for backward compatibility
-  static fromCode(
-    code: CredentialErrorCode,
-    message: string,
-    details?: any
-  ): CredentialManagerError {
+  static fromCode(code: CredentialErrorCode, message: string, details?: any): CredentialManagerError {
     // Map codes to types
-    let type: ErrorType;
+    let type: ErrorType
     if (code.includes('CONFIG')) {
-      type = ErrorType.CONFIG_LOAD_ERROR;
+      type = ErrorType.CONFIG_LOAD_ERROR
     } else if (code.includes('SIGNING') || code.includes('VERIFICATION')) {
-      type = ErrorType.SIGNATURE_ERROR;
+      type = ErrorType.SIGNATURE_ERROR
     } else if (code.includes('PLATFORM')) {
-      type = ErrorType.PLATFORM_DETECTION_ERROR;
+      type = ErrorType.PLATFORM_DETECTION_ERROR
     } else {
-      type = ErrorType.VALIDATION_ERROR;
+      type = ErrorType.VALIDATION_ERROR
     }
 
-    return new CredentialManagerError(message, type, details);
+    return new CredentialManagerError(message, type, details)
   }
 }
 
@@ -354,64 +356,64 @@ export class CredentialManagerError extends Error {
  * Sign request interface
  */
 export interface SignRequest {
-  accountId: string;
-  message: Uint8Array;
-  options?: SignOptions;
+  accountId: string
+  message: Uint8Array
+  options?: SignOptions
 }
 
 /**
  * Sign options
  */
 export interface SignOptions {
-  timeout?: number; // milliseconds
-  algorithm?: SignatureType;
-  encoding?: 'base64' | 'hex' | 'base58';
-  metadata?: Record<string, any>;
+  timeout?: number // milliseconds
+  algorithm?: SignatureType
+  encoding?: 'base64' | 'hex' | 'base58'
+  metadata?: Record<string, any>
 }
 
 /**
  * Sign result interface
  */
 export interface SignResult {
-  success: boolean;
-  signature?: string;
-  algorithm: string;
-  timestamp: Date;
-  duration?: number; // milliseconds
-  error?: string;
-  metadata?: Record<string, any>;
+  success: boolean
+  signature?: string
+  algorithm: string
+  timestamp: Date
+  duration?: number // milliseconds
+  error?: string
+  metadata?: Record<string, any>
 }
 
 /**
  * Verify request interface
  */
 export interface VerifyRequest {
-  accountId: string;
-  message: Uint8Array;
-  signature: string;
-  options?: VerifyOptions;
+  accountId: string
+  message: Uint8Array
+  signature: string
+  options?: VerifyOptions
 }
 
 /**
  * Verify options
  */
 export interface VerifyOptions {
-  timeout?: number; // milliseconds
-  publicKey?: string;
-  algorithm?: SignatureType;
-  metadata?: Record<string, any>;
+  timeout?: number // milliseconds
+  publicKey?: string
+  algorithm?: SignatureType
+  metadata?: Record<string, any>
 }
 
 /**
  * Verify result interface
  */
 export interface VerifyResponse {
-  isValid: boolean;
-  algorithm: string;
-  timestamp: Date;
-  duration?: number; // milliseconds
-  error?: string;
-  metadata?: Record<string, any>;
+  isValid: boolean
+  algorithm: string
+  timestamp: Date
+  duration?: number // milliseconds
+  error?: string
+  metadata?: Record<string, any>
 }
 
 // ============================================================================
@@ -427,32 +429,32 @@ export interface ICredentialManager {
    * @param filePath Configuration file path
    * @returns Load result
    */
-  loadConfig(filePath: string): Promise<LoadResult>;
+  loadConfig(filePath: string): Promise<LoadResult>
 
   /**
    * Watch configuration file for changes
    * @param filePath Configuration file path
    * @param callback Change callback function
    */
-  watchConfig(filePath: string, callback: (accounts: Account[]) => void): void;
+  watchConfig(filePath: string, callback: (accounts: Account[]) => void): void
 
   /**
    * Stop watching configuration file
    */
-  stopWatching(): void;
+  stopWatching(): void
 
   /**
    * Get account by ID
    * @param accountId Account ID
    * @returns Account or null if not found
    */
-  getAccount(accountId: string): Account | null;
+  getAccount(accountId: string): Account | null
 
   /**
    * List all accounts
    * @returns Array of accounts
    */
-  listAccounts(): Account[];
+  listAccounts(): Account[]
 
   /**
    * Sign message with account
@@ -460,7 +462,7 @@ export interface ICredentialManager {
    * @param message Message to sign
    * @returns Sign result
    */
-  sign(accountId: string, message: Uint8Array): Promise<SignResult>;
+  sign(accountId: string, message: Uint8Array): Promise<SignResult>
 
   /**
    * Verify signature
@@ -469,7 +471,7 @@ export interface ICredentialManager {
    * @param signature Signature string
    * @returns Verification result
    */
-  verify(accountId: string, message: Uint8Array, signature: string): Promise<boolean>;
+  verify(accountId: string, message: Uint8Array, signature: string): Promise<boolean>
 }
 
 // ============================================================================
@@ -481,50 +483,50 @@ export interface ICredentialManager {
  */
 export interface PerformanceMetrics {
   // Configuration metrics
-  configLoadTime: number; // milliseconds
-  configWatchLatency: number; // milliseconds
+  configLoadTime: number // milliseconds
+  configWatchLatency: number // milliseconds
 
   // Signing metrics
-  signOperationsTotal: number;
-  signOperationsSuccess: number;
-  signOperationsFailed: number;
-  averageSignTime: number; // milliseconds
-  maxSignTime: number; // milliseconds
-  minSignTime: number; // milliseconds
+  signOperationsTotal: number
+  signOperationsSuccess: number
+  signOperationsFailed: number
+  averageSignTime: number // milliseconds
+  maxSignTime: number // milliseconds
+  minSignTime: number // milliseconds
 
   // Verification metrics
-  verifyOperationsTotal: number;
-  verifyOperationsSuccess: number;
-  verifyOperationsFailed: number;
-  averageVerifyTime: number; // milliseconds
+  verifyOperationsTotal: number
+  verifyOperationsSuccess: number
+  verifyOperationsFailed: number
+  averageVerifyTime: number // milliseconds
 
   // Memory metrics
-  memoryUsage: number; // bytes
-  accountCount: number;
+  memoryUsage: number // bytes
+  accountCount: number
 
   // Error metrics
-  errorsByCode: Record<CredentialErrorCode, number>;
+  errorsByCode: Record<CredentialErrorCode, number>
 
   // Timing
-  lastResetAt: Date;
-  uptime: number; // milliseconds
+  lastResetAt: Date
+  uptime: number // milliseconds
 }
 
 /**
  * Health check interface
  */
 export interface HealthCheck {
-  healthy: boolean;
+  healthy: boolean
   components: {
-    configLoader: boolean;
-    fileWatcher: boolean;
-    signers: Record<Platform, boolean>;
-  };
+    configLoader: boolean
+    fileWatcher: boolean
+    signers: Record<Platform, boolean>
+  }
   performance: {
-    configLoadTime: number;
-    averageSignTime: number;
-    memoryUsage: number;
-  };
-  errors?: CredentialError[];
-  timestamp: Date;
-}
+    configLoadTime: number
+    averageSignTime: number
+    memoryUsage: number
+  }
+  errors?: CredentialError[]
+  timestamp: Date
+}

+ 2 - 0
src/utils/httpClient.ts

@@ -1,5 +1,7 @@
 import { HttpsProxyAgent } from 'https-proxy-agent'
+
 import { Config } from '@/config/simpleEnv'
+
 import { logger } from './logger'
 
 /**

+ 3 - 0
src/utils/universalHttpClient.ts

@@ -8,7 +8,9 @@
  */
 
 import { EventEmitter } from 'events'
+
 import { v4 as uuidv4 } from 'uuid'
+
 import type {
   HttpClientRequest,
   HttpClientResponse,
@@ -22,6 +24,7 @@ import type {
   ResponseMetadata,
 } from '@/types/httpClient'
 import type { PlatformConfig, IPlatformAdapter, PlatformRequest } from '@/types/platformAdapter'
+
 import { HttpClient } from './httpClient'
 
 // 临时接口定义,后续将从其他模块迁移

File diff suppressed because it is too large
+ 709 - 18
yarn.lock


Some files were not shown because too many files changed in this diff