Browse Source

refactor: simplify spec kit workflow and clean up obsolete files

- Remove custom branch management constraints from create-new-feature.sh
- Delete obsolete spec directories (001-specManager-perp, 002-credential-manager)
- Clean up legacy hedging and account management source files
- Remove manage-branches.sh and related documentation
- Simplify feature creation workflow for better developer experience

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

Co-Authored-By: Claude <noreply@anthropic.com>
helium3@sina.com 2 months ago
parent
commit
b5acbef214
32 changed files with 5339 additions and 4930 deletions
  1. 0 255
      .specify/docs/branch-management.md
  2. 3 22
      .specify/scripts/bash/create-new-feature.sh
  3. 0 305
      .specify/scripts/bash/manage-branches.sh
  4. 1 1
      .specify/templates/plan-template.md
  5. 0 0
      backup/features/20250928/001-specManager-perp/contracts/README.md
  6. 0 0
      backup/features/20250928/001-specManager-perp/contracts/account-sync.md
  7. 0 0
      backup/features/20250928/001-specManager-perp/contracts/hedge-execution.md
  8. 0 0
      backup/features/20250928/001-specManager-perp/contracts/market-data-failover.md
  9. 0 0
      backup/features/20250928/001-specManager-perp/data-model.md
  10. 0 0
      backup/features/20250928/001-specManager-perp/plan.md
  11. 0 0
      backup/features/20250928/001-specManager-perp/quickstart.md
  12. 0 0
      backup/features/20250928/001-specManager-perp/research.md
  13. 0 0
      backup/features/20250928/001-specManager-perp/spec.md
  14. 0 0
      backup/features/20250928/001-specManager-perp/tasks.md
  15. 0 0
      backup/features/20250928/002-credential-manager/contracts/signature-service.md
  16. 0 0
      backup/features/20250928/002-credential-manager/data-model.md
  17. 0 0
      backup/features/20250928/002-credential-manager/plan.md
  18. 0 0
      backup/features/20250928/002-credential-manager/quickstart.md
  19. 0 0
      backup/features/20250928/002-credential-manager/research.md
  20. 0 0
      backup/features/20250928/002-credential-manager/spec.md
  21. 0 0
      backup/features/20250928/002-credential-manager/tasks.md
  22. 5324 0
      libs/credential-manager/package-lock.json
  23. 11 0
      libs/credential-manager/test_simple.mjs
  24. 0 873
      src/core/accounts/manager.ts
  25. 0 391
      src/core/accounts/models.ts
  26. 0 898
      src/core/hedging/SamePlatformHedgingManager.ts
  27. 0 362
      src/core/hedging/UnifiedHedgingExecutor.ts
  28. 0 49
      src/core/hedging/hedgeCalculator.ts
  29. 0 65
      src/core/hedging/router.ts
  30. 0 69
      src/core/hedging/types.ts
  31. 0 988
      src/core/risk/controller.ts
  32. 0 652
      src/core/risk/envelope.ts

+ 0 - 255
.specify/docs/branch-management.md

@@ -1,255 +0,0 @@
-# Spec Kit 分支管理规范
-
-## 📋 概述
-
-本文档定义了Spec Kit的自动化分支管理流程,旨在防止分支累积,确保开发流程清洁高效。
-
-## 🎯 设计原则
-
-### 1. **一个功能一个分支**
-- 每个`/specify`命令创建独立的功能分支
-- 分支命名格式:`001-功能名`, `002-功能名`
-- 避免在同一分支中混合多个功能
-
-### 2. **完成后立即合并**
-- 功能完成后立即合并到main分支
-- 合并后删除功能分支
-- 避免长期存在的功能分支
-
-### 3. **智能检查防护**
-- 创建新分支前检查现有分支状态
-- 多分支存在时提示清理
-- 提供自动化清理工具
-
-## 🔧 自动化工具
-
-### 核心脚本
-
-#### `manage-branches.sh`
-主要的分支管理脚本,提供以下功能:
-
-```bash
-# 查看分支状态
-./manage-branches.sh --status
-
-# 交互式分支清理
-./manage-branches.sh --cleanup
-
-# 自动合并当前分支
-./manage-branches.sh --merge
-
-# 新功能创建前检查
-./manage-branches.sh --check
-```
-
-#### `spec-branch` (便捷工具)
-简化的命令行界面:
-
-```bash
-# 查看状态
-spec-branch status
-
-# 清理分支
-spec-branch clean
-
-# 合并当前分支
-spec-branch merge
-
-# 检查分支状态
-spec-branch check
-```
-
-### 集成的创建流程
-
-`create-new-feature.sh`已集成分支检查:
-
-```bash
-# 正常创建(包含分支检查)
-./create-new-feature.sh "新功能描述"
-
-# 跳过分支检查(紧急情况)
-./create-new-feature.sh --skip-check "新功能描述"
-```
-
-## 🚀 使用流程
-
-### 日常开发工作流
-
-#### 1. **创建新功能前**
-```bash
-# 检查分支状态
-spec-branch check
-
-# 如果有多分支,先清理
-spec-branch clean
-```
-
-#### 2. **功能开发中**
-- 专注当前分支开发
-- 定期提交代码
-- 避免切换到其他功能分支
-
-#### 3. **功能完成后**
-```bash
-# 自动合并当前分支到main
-spec-branch merge
-
-# 或手动合并流程
-git add .
-git commit -m "完成功能实现"
-git checkout main
-git merge <feature-branch>
-git branch -d <feature-branch>
-```
-
-### 分支状态管理
-
-#### 分支状态分析
-脚本会分析以下信息:
-- **Spec目录**: 是否存在specs目录
-- **代码实现**: src目录中的变更文件数
-- **提交数量**: 相对main分支的提交数
-
-#### 清理策略
-```bash
-# 查看详细状态
-spec-branch status
-
-# 交互式清理(推荐)
-spec-branch clean
-```
-
-交互式清理提供选项:
-1. **保留分支** - 继续开发
-2. **删除分支** - 丢弃变更(谨慎!)
-3. **合并到main** - 完成功能
-4. **跳过** - 稍后处理
-
-## ⚠️ 最佳实践
-
-### DO ✅
-- 每次创建新功能前运行分支检查
-- 功能完成后立即合并
-- 使用便捷工具简化操作
-- 定期运行 `spec-branch status` 检查状态
-
-### DON'T ❌
-- 不要同时开发多个功能分支
-- 不要长期保留已完成的分支
-- 不要跳过分支检查(除非紧急)
-- 不要在main分支直接开发
-
-### 紧急情况处理
-
-#### 强制创建分支
-```bash
-# 跳过检查创建紧急分支
-./create-new-feature.sh --skip-check "紧急修复"
-```
-
-#### 批量清理
-```bash
-# 查看所有分支
-git branch -v
-
-# 删除已合并的分支
-git branch --merged main | grep -v main | xargs git branch -d
-
-# 强制删除未合并分支(谨慎!)
-git branch -D <branch-name>
-```
-
-## 🔧 配置和自定义
-
-### 环境变量
-- `SKIP_BRANCH_CHECK=true` - 全局跳过分支检查
-- `MAIN_BRANCH=develop` - 自定义主分支名称
-
-### 自定义检查规则
-修改`manage-branches.sh`中的检查逻辑:
-
-```bash
-# 修改最大允许分支数
-MAX_BRANCHES=2
-
-# 修改警告阈值
-WARN_THRESHOLD=1
-```
-
-## 📊 监控和报告
-
-### 分支健康度检查
-```bash
-# 定期运行分支状态检查
-spec-branch status
-
-# 查看分支历史
-git branch -v
-git log --oneline --graph --all
-```
-
-### 指标追踪
-- 平均分支生命周期
-- 分支合并频率
-- 未完成分支数量
-
-## 🔄 版本控制集成
-
-### Git Hooks(可选)
-在`.git/hooks/pre-push`中添加检查:
-
-```bash
-#!/bin/bash
-# 推送前检查分支状态
-./.specify/scripts/bash/manage-branches.sh --check
-```
-
-### CI/CD集成
-在构建流程中添加分支检查:
-
-```yaml
-- name: Check branch status
-  run: ./.specify/scripts/bash/manage-branches.sh --status
-```
-
-## 🛠️ 故障排除
-
-### 常见问题
-
-#### 问题1: 分支检查失败
-```bash
-# 检查脚本权限
-chmod +x .specify/scripts/bash/manage-branches.sh
-
-# 检查Git状态
-git status
-```
-
-#### 问题2: 合并冲突
-```bash
-# 解决冲突后继续合并
-git add .
-git commit -m "解决合并冲突"
-spec-branch merge
-```
-
-#### 问题3: 无法删除分支
-```bash
-# 强制删除
-git branch -D <branch-name>
-
-# 清理远程分支引用
-git remote prune origin
-```
-
-## 📚 相关文档
-
-- [Spec Kit 使用指南](./spec-kit-guide.md)
-- [功能开发流程](./feature-development.md)
-- [Git 工作流规范](./git-workflow.md)
-
----
-
-**版本**: 1.0.0
-**更新日期**: 2025-09-28
-**维护者**: Spec Kit Team

+ 3 - 22
.specify/scripts/bash/create-new-feature.sh

@@ -7,7 +7,7 @@ ARGS=()
 for arg in "$@"; do
     case "$arg" in
         --json) JSON_MODE=true ;;
-        --help|-h) echo "Usage: $0 [--json] [--skip-check] <feature_description>"; exit 0 ;;
+        --help|-h) echo "Usage: $0 [--json] <feature_description>"; exit 0 ;;
         *) ARGS+=("$arg") ;;
     esac
 done
@@ -18,13 +18,7 @@ if [ -z "$FEATURE_DESCRIPTION" ]; then
     exit 1
 fi
 
-# 添加分支管理检查 - 可以通过 --skip-check 跳过
-SKIP_BRANCH_CHECK=false
-for arg in "$@"; do
-    case "$arg" in
-        --skip-check) SKIP_BRANCH_CHECK=true ;;
-    esac
-done
+# Removed custom branch management check
 
 # Function to find the repository root by searching for existing project markers
 find_repo_root() {
@@ -58,20 +52,7 @@ fi
 
 cd "$REPO_ROOT"
 
-# 分支管理检查 (除非跳过)
-if [ "$SKIP_BRANCH_CHECK" = false ] && [ "$HAS_GIT" = true ]; then
-    MANAGE_SCRIPT="$REPO_ROOT/.specify/scripts/bash/manage-branches.sh"
-    if [ -x "$MANAGE_SCRIPT" ]; then
-        echo "🔍 检查分支状态..."
-        if ! "$MANAGE_SCRIPT" --check; then
-            echo ""
-            echo "💡 建议先清理现有分支,或使用 --skip-check 跳过检查"
-            echo "运行: $MANAGE_SCRIPT --cleanup"
-            exit 1
-        fi
-        echo ""
-    fi
-fi
+# Branch management check removed for simplified workflow
 
 SPECS_DIR="$REPO_ROOT/specs"
 mkdir -p "$SPECS_DIR"

+ 0 - 305
.specify/scripts/bash/manage-branches.sh

@@ -1,305 +0,0 @@
-#!/usr/bin/env bash
-
-# 分支管理自动化脚本
-# 实现智能分支检查、清理和流程指导
-
-set -e
-
-# 颜色定义
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-YELLOW='\033[1;33m'
-BLUE='\033[0;34m'
-NC='\033[0m' # No Color
-
-# 获取仓库根目录
-get_repo_root() {
-    if git rev-parse --show-toplevel >/dev/null 2>&1; then
-        git rev-parse --show-toplevel
-    else
-        echo "Error: 不是Git仓库或未初始化Git" >&2
-        exit 1
-    fi
-}
-
-# 分析分支状态
-analyze_branches() {
-    local repo_root="$1"
-    local current_branch=$(git branch --show-current)
-    local main_branch="main"
-
-    echo -e "${BLUE}📊 分支状态分析${NC}"
-    echo "===================================="
-
-    # 列出所有功能分支
-    local feature_branches=()
-    while IFS= read -r branch; do
-        branch=$(echo "$branch" | sed 's/^[* ] //')
-        if [[ "$branch" =~ ^[0-9]{3}- ]] && [[ "$branch" != "$main_branch" ]]; then
-            feature_branches+=("$branch")
-        fi
-    done < <(git branch)
-
-    if [ ${#feature_branches[@]} -eq 0 ]; then
-        echo -e "${GREEN}✅ 无功能分支,分支状态干净${NC}"
-        return 0
-    fi
-
-    echo -e "${YELLOW}📋 发现 ${#feature_branches[@]} 个功能分支:${NC}"
-
-    for branch in "${feature_branches[@]}"; do
-        local spec_dir="$repo_root/specs/$branch"
-        local has_spec_dir=""
-        local has_implementation=""
-        local commits_ahead=""
-
-        # 检查是否有specs目录
-        if [ -d "$spec_dir" ]; then
-            has_spec_dir="✅"
-        else
-            has_spec_dir="❌"
-        fi
-
-        # 检查是否有实现代码(src目录中的变更)
-        local changed_files=$(git diff --name-only "$main_branch..$branch" 2>/dev/null | grep "^src/" | wc -l || echo "0")
-        if [ "$changed_files" -gt 0 ]; then
-            has_implementation="✅ ($changed_files files)"
-        else
-            has_implementation="❌"
-        fi
-
-        # 检查相对main的提交数
-        commits_ahead=$(git rev-list --count "$main_branch..$branch" 2>/dev/null || echo "0")
-
-        # 输出分支状态
-        printf "  %-25s | Spec: %s | Code: %-12s | Commits: %s\n" \
-               "$branch" "$has_spec_dir" "$has_implementation" "$commits_ahead"
-    done
-
-    echo ""
-    return ${#feature_branches[@]}
-}
-
-# 建议操作
-suggest_actions() {
-    local branch_count=$1
-    local current_branch=$(git branch --show-current)
-
-    echo -e "${BLUE}💡 建议操作${NC}"
-    echo "===================================="
-
-    if [ "$branch_count" -eq 0 ]; then
-        echo -e "${GREEN}✨ 可以安全创建新功能分支${NC}"
-        return 0
-    fi
-
-    if [ "$branch_count" -eq 1 ] && [[ "$current_branch" =~ ^[0-9]{3}- ]]; then
-        echo -e "${YELLOW}🎯 专注完成当前分支: $current_branch${NC}"
-        echo "建议: 完成后运行 'manage-branches.sh --merge' 合并到main"
-    elif [ "$branch_count" -ge 2 ]; then
-        echo -e "${RED}⚠️  发现多个功能分支,建议清理${NC}"
-        echo "选项1: 删除重复或不需要的分支"
-        echo "选项2: 完成并合并已完成的分支"
-        echo "选项3: 运行 'manage-branches.sh --cleanup' 进行交互式清理"
-    fi
-}
-
-# 交互式分支清理
-interactive_cleanup() {
-    local repo_root="$1"
-    local current_branch=$(git branch --show-current)
-    local main_branch="main"
-
-    echo -e "${BLUE}🧹 交互式分支清理${NC}"
-    echo "===================================="
-
-    # 获取所有功能分支
-    local feature_branches=()
-    while IFS= read -r branch; do
-        branch=$(echo "$branch" | sed 's/^[* ] //')
-        if [[ "$branch" =~ ^[0-9]{3}- ]] && [[ "$branch" != "$main_branch" ]]; then
-            feature_branches+=("$branch")
-        fi
-    done < <(git branch)
-
-    if [ ${#feature_branches[@]} -eq 0 ]; then
-        echo -e "${GREEN}✅ 没有需要清理的功能分支${NC}"
-        return 0
-    fi
-
-    for branch in "${feature_branches[@]}"; do
-        echo ""
-        echo -e "${YELLOW}📝 分支: $branch${NC}"
-
-        # 显示分支信息
-        local commits=$(git rev-list --count "$main_branch..$branch" 2>/dev/null || echo "0")
-        local spec_dir="$repo_root/specs/$branch"
-
-        echo "  提交数: $commits"
-        if [ -d "$spec_dir" ]; then
-            echo "  规范目录: ✅ $spec_dir"
-        else
-            echo "  规范目录: ❌ 不存在"
-        fi
-
-        # 询问操作
-        echo ""
-        echo "选择操作:"
-        echo "  1) 保留分支"
-        echo "  2) 删除分支 (谨慎!)"
-        echo "  3) 合并到main并删除"
-        echo "  4) 跳过"
-
-        read -p "请选择 (1-4): " choice
-
-        case $choice in
-            1)
-                echo -e "${GREEN}✅ 保留分支 $branch${NC}"
-                ;;
-            2)
-                echo -e "${RED}⚠️  确认删除分支 $branch? 这将丢失所有变更!${NC}"
-                read -p "输入 'DELETE' 确认: " confirm
-                if [ "$confirm" = "DELETE" ]; then
-                    git branch -D "$branch"
-                    rm -rf "$spec_dir"
-                    echo -e "${RED}🗑️  已删除分支 $branch${NC}"
-                else
-                    echo -e "${YELLOW}❌ 取消删除${NC}"
-                fi
-                ;;
-            3)
-                echo -e "${BLUE}🔄 合并分支 $branch 到 main${NC}"
-                # 检查是否有未提交的变更
-                if ! git diff-index --quiet HEAD --; then
-                    echo -e "${YELLOW}⚠️  当前分支有未提交的变更,请先提交${NC}"
-                    continue
-                fi
-
-                # 切换到main并合并
-                git checkout main
-                git merge "$branch"
-                git branch -d "$branch"
-                echo -e "${GREEN}✅ 已合并并删除分支 $branch${NC}"
-                ;;
-            4)
-                echo -e "${BLUE}⏭️  跳过分支 $branch${NC}"
-                ;;
-            *)
-                echo -e "${RED}❌ 无效选择,跳过${NC}"
-                ;;
-        esac
-    done
-}
-
-# 自动合并当前分支
-auto_merge_current() {
-    local current_branch=$(git branch --show-current)
-    local main_branch="main"
-
-    if [[ ! "$current_branch" =~ ^[0-9]{3}- ]]; then
-        echo -e "${RED}❌ 当前不在功能分支上${NC}"
-        exit 1
-    fi
-
-    echo -e "${BLUE}🔄 自动合并当前分支: $current_branch${NC}"
-
-    # 检查是否有未提交的变更
-    if ! git diff-index --quiet HEAD --; then
-        echo -e "${YELLOW}⚠️  发现未提交的变更,正在提交...${NC}"
-        git add .
-        git commit -m "完成功能实现 - 自动提交"
-    fi
-
-    # 切换到main并合并
-    git checkout main
-    git merge "$current_branch" --no-ff -m "合并功能分支: $current_branch"
-    git branch -d "$current_branch"
-
-    echo -e "${GREEN}✅ 已成功合并并删除分支: $current_branch${NC}"
-}
-
-# 检查新功能创建前的状态
-pre_create_check() {
-    echo -e "${BLUE}🔍 新功能创建前检查${NC}"
-    echo "===================================="
-
-    local branch_count
-    analyze_branches "$(get_repo_root)"
-    branch_count=$?
-
-    if [ "$branch_count" -eq 0 ]; then
-        echo -e "${GREEN}✅ 可以安全创建新功能分支${NC}"
-        return 0
-    elif [ "$branch_count" -eq 1 ]; then
-        local current_branch=$(git branch --show-current)
-        if [[ "$current_branch" =~ ^[0-9]{3}- ]]; then
-            echo -e "${YELLOW}⚠️  建议先完成当前分支: $current_branch${NC}"
-            echo "运行 'manage-branches.sh --merge' 来合并当前分支"
-        else
-            echo -e "${YELLOW}⚠️  发现1个功能分支,建议清理后再创建新功能${NC}"
-        fi
-        return 1
-    else
-        echo -e "${RED}🚫 发现多个功能分支,强烈建议先清理${NC}"
-        echo "运行 'manage-branches.sh --cleanup' 进行清理"
-        return 2
-    fi
-}
-
-# 显示帮助信息
-show_help() {
-    echo "分支管理自动化工具"
-    echo ""
-    echo "用法: $0 [选项]"
-    echo ""
-    echo "选项:"
-    echo "  --status     显示分支状态分析"
-    echo "  --cleanup    交互式分支清理"
-    echo "  --merge      自动合并当前功能分支到main"
-    echo "  --check      新功能创建前检查"
-    echo "  --help       显示帮助信息"
-    echo ""
-    echo "示例:"
-    echo "  $0 --status          # 查看当前分支状态"
-    echo "  $0 --check           # 检查是否适合创建新功能"
-    echo "  $0 --cleanup         # 交互式清理分支"
-    echo "  $0 --merge           # 合并当前分支到main"
-}
-
-# 主函数
-main() {
-    local repo_root
-    repo_root=$(get_repo_root)
-    cd "$repo_root"
-
-    case "${1:-}" in
-        --status)
-            analyze_branches "$repo_root"
-            suggest_actions $?
-            ;;
-        --cleanup)
-            interactive_cleanup "$repo_root"
-            ;;
-        --merge)
-            auto_merge_current
-            ;;
-        --check)
-            pre_create_check
-            ;;
-        --help|-h)
-            show_help
-            ;;
-        "")
-            # 默认行为:显示状态和建议
-            analyze_branches "$repo_root"
-            suggest_actions $?
-            ;;
-        *)
-            echo -e "${RED}❌ 未知选项: $1${NC}" >&2
-            show_help
-            exit 1
-            ;;
-    esac
-}
-
-main "$@"

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

@@ -143,7 +143,7 @@ ios/ 或 android/
    - 每个故事 → 集成测试场景
    - Quickstart 测试 = 验收步骤
 5. **增量更新 agent 文件**(O(1) 操作):
-   - 运行 `.specify/scripts/bash/update-agent-context.sh cursor`
+   - 运行 `.specify/scripts/bash/update-agent-context.sh claude`
    - 仅添加本轮新增技术信息
    - 保留手工补充内容
    - 记录最近 3 次变更

+ 0 - 0
specs/001-specManager-perp/contracts/README.md → backup/features/20250928/001-specManager-perp/contracts/README.md


+ 0 - 0
specs/001-specManager-perp/contracts/account-sync.md → backup/features/20250928/001-specManager-perp/contracts/account-sync.md


+ 0 - 0
specs/001-specManager-perp/contracts/hedge-execution.md → backup/features/20250928/001-specManager-perp/contracts/hedge-execution.md


+ 0 - 0
specs/001-specManager-perp/contracts/market-data-failover.md → backup/features/20250928/001-specManager-perp/contracts/market-data-failover.md


+ 0 - 0
specs/001-specManager-perp/data-model.md → backup/features/20250928/001-specManager-perp/data-model.md


+ 0 - 0
specs/001-specManager-perp/plan.md → backup/features/20250928/001-specManager-perp/plan.md


+ 0 - 0
specs/001-specManager-perp/quickstart.md → backup/features/20250928/001-specManager-perp/quickstart.md


+ 0 - 0
specs/001-specManager-perp/research.md → backup/features/20250928/001-specManager-perp/research.md


+ 0 - 0
specs/001-specManager-perp/spec.md → backup/features/20250928/001-specManager-perp/spec.md


+ 0 - 0
specs/001-specManager-perp/tasks.md → backup/features/20250928/001-specManager-perp/tasks.md


+ 0 - 0
specs/002-credential-manager/contracts/signature-service.md → backup/features/20250928/002-credential-manager/contracts/signature-service.md


+ 0 - 0
specs/002-credential-manager/data-model.md → backup/features/20250928/002-credential-manager/data-model.md


+ 0 - 0
specs/002-credential-manager/plan.md → backup/features/20250928/002-credential-manager/plan.md


+ 0 - 0
specs/002-credential-manager/quickstart.md → backup/features/20250928/002-credential-manager/quickstart.md


+ 0 - 0
specs/002-credential-manager/research.md → backup/features/20250928/002-credential-manager/research.md


+ 0 - 0
specs/002-credential-manager/spec.md → backup/features/20250928/002-credential-manager/spec.md


+ 0 - 0
specs/002-credential-manager/tasks.md → backup/features/20250928/002-credential-manager/tasks.md


+ 5324 - 0
libs/credential-manager/package-lock.json

@@ -0,0 +1,5324 @@
+{
+  "name": "@binance-api/credential-manager",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "@binance-api/credential-manager",
+      "version": "1.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "@noble/ed25519": "^2.0.0",
+        "@noble/hashes": "^1.3.0"
+      },
+      "devDependencies": {
+        "@types/jest": "^29.5.0",
+        "@types/node": "^18.15.0",
+        "@typescript-eslint/eslint-plugin": "^5.57.0",
+        "@typescript-eslint/parser": "^5.57.0",
+        "eslint": "^8.37.0",
+        "eslint-config-prettier": "^8.8.0",
+        "eslint-plugin-prettier": "^4.2.1",
+        "jest": "^29.5.0",
+        "prettier": "^2.8.7",
+        "rimraf": "^4.4.1",
+        "ts-jest": "^29.1.0",
+        "typescript": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+      "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.27.1",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
+      "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
+      "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@babel/generator": "^7.28.3",
+        "@babel/helper-compilation-targets": "^7.27.2",
+        "@babel/helper-module-transforms": "^7.28.3",
+        "@babel/helpers": "^7.28.4",
+        "@babel/parser": "^7.28.4",
+        "@babel/template": "^7.27.2",
+        "@babel/traverse": "^7.28.4",
+        "@babel/types": "^7.28.4",
+        "@jridgewell/remapping": "^2.3.5",
+        "convert-source-map": "^2.0.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.28.3",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
+      "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.28.3",
+        "@babel/types": "^7.28.2",
+        "@jridgewell/gen-mapping": "^0.3.12",
+        "@jridgewell/trace-mapping": "^0.3.28",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.27.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+      "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.27.2",
+        "@babel/helper-validator-option": "^7.27.1",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-globals": {
+      "version": "7.28.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+      "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+      "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.27.1",
+        "@babel/types": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.28.3",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
+      "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.27.1",
+        "@babel/helper-validator-identifier": "^7.27.1",
+        "@babel/traverse": "^7.28.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+      "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+      "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+      "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+      "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
+      "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.27.2",
+        "@babel/types": "^7.28.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
+      "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.28.4"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-bigint": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+      "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-properties": {
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.12.13"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-static-block": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
+      "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-attributes": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz",
+      "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
+      "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-private-property-in-object": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
+      "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz",
+      "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.27.2",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+      "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@babel/parser": "^7.27.2",
+        "@babel/types": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
+      "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@babel/generator": "^7.28.3",
+        "@babel/helper-globals": "^7.28.0",
+        "@babel/parser": "^7.28.4",
+        "@babel/template": "^7.27.2",
+        "@babel/types": "^7.28.4",
+        "debug": "^4.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
+      "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.27.1",
+        "@babel/helper-validator-identifier": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@bcoe/v8-coverage": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
+      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.9.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
+      "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eslint-visitor-keys": "^3.4.3"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+      }
+    },
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+      "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.6.0",
+        "globals": "^13.19.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "8.57.1",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+      "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array": {
+      "version": "0.13.0",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+      "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+      "deprecated": "Use @eslint/config-array instead",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@humanwhocodes/object-schema": "^2.0.3",
+        "debug": "^4.3.1",
+        "minimatch": "^3.0.5"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      }
+    },
+    "node_modules/@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/object-schema": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+      "deprecated": "Use @eslint/object-schema instead",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/console": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz",
+      "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "jest-message-util": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/core": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz",
+      "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/console": "^29.7.0",
+        "@jest/reporters": "^29.7.0",
+        "@jest/test-result": "^29.7.0",
+        "@jest/transform": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.9",
+        "jest-changed-files": "^29.7.0",
+        "jest-config": "^29.7.0",
+        "jest-haste-map": "^29.7.0",
+        "jest-message-util": "^29.7.0",
+        "jest-regex-util": "^29.6.3",
+        "jest-resolve": "^29.7.0",
+        "jest-resolve-dependencies": "^29.7.0",
+        "jest-runner": "^29.7.0",
+        "jest-runtime": "^29.7.0",
+        "jest-snapshot": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "jest-validate": "^29.7.0",
+        "jest-watcher": "^29.7.0",
+        "micromatch": "^4.0.4",
+        "pretty-format": "^29.7.0",
+        "slash": "^3.0.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@jest/environment": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
+      "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/fake-timers": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "jest-mock": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/expect": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz",
+      "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "expect": "^29.7.0",
+        "jest-snapshot": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/expect-utils": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
+      "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jest-get-type": "^29.6.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/fake-timers": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
+      "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.6.3",
+        "@sinonjs/fake-timers": "^10.0.2",
+        "@types/node": "*",
+        "jest-message-util": "^29.7.0",
+        "jest-mock": "^29.7.0",
+        "jest-util": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/globals": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
+      "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/environment": "^29.7.0",
+        "@jest/expect": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "jest-mock": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/reporters": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz",
+      "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@bcoe/v8-coverage": "^0.2.3",
+        "@jest/console": "^29.7.0",
+        "@jest/test-result": "^29.7.0",
+        "@jest/transform": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@jridgewell/trace-mapping": "^0.3.18",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-instrument": "^6.0.0",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.1.3",
+        "jest-message-util": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "jest-worker": "^29.7.0",
+        "slash": "^3.0.0",
+        "string-length": "^4.0.1",
+        "strip-ansi": "^6.0.0",
+        "v8-to-istanbul": "^9.0.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@jest/schemas": {
+      "version": "29.6.3",
+      "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+      "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@sinclair/typebox": "^0.27.8"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/source-map": {
+      "version": "29.6.3",
+      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
+      "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.18",
+        "callsites": "^3.0.0",
+        "graceful-fs": "^4.2.9"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/test-result": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz",
+      "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/console": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "collect-v8-coverage": "^1.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/test-sequencer": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
+      "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/test-result": "^29.7.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.7.0",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/transform": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
+      "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.11.6",
+        "@jest/types": "^29.6.3",
+        "@jridgewell/trace-mapping": "^0.3.18",
+        "babel-plugin-istanbul": "^6.1.1",
+        "chalk": "^4.0.0",
+        "convert-source-map": "^2.0.0",
+        "fast-json-stable-stringify": "^2.1.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.7.0",
+        "jest-regex-util": "^29.6.3",
+        "jest-util": "^29.7.0",
+        "micromatch": "^4.0.4",
+        "pirates": "^4.0.4",
+        "slash": "^3.0.0",
+        "write-file-atomic": "^4.0.2"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jest/types": {
+      "version": "29.6.3",
+      "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+      "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/schemas": "^29.6.3",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "@types/istanbul-reports": "^3.0.0",
+        "@types/node": "*",
+        "@types/yargs": "^17.0.8",
+        "chalk": "^4.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/remapping": {
+      "version": "2.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@noble/ed25519": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.3.0.tgz",
+      "integrity": "sha512-M7dvXL2B92/M7dw9+gzuydL8qn/jiqNHaoR3Q+cb1q1GHV7uwE17WCyFMG+Y+TZb5izcaXk5TdJRrDUxHXL78A==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@noble/hashes": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
+      "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
+      "license": "MIT",
+      "engines": {
+        "node": "^14.21.3 || >=16"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@sinclair/typebox": {
+      "version": "0.27.8",
+      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+      "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@sinonjs/commons": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
+      "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "type-detect": "4.0.8"
+      }
+    },
+    "node_modules/@sinonjs/fake-timers": {
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
+      "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@sinonjs/commons": "^3.0.0"
+      }
+    },
+    "node_modules/@types/babel__core": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+      "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "node_modules/@types/babel__generator": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+      "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__template": {
+      "version": "7.4.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+      "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__traverse": {
+      "version": "7.28.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+      "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.28.2"
+      }
+    },
+    "node_modules/@types/graceful-fs": {
+      "version": "4.1.9",
+      "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
+      "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/istanbul-lib-coverage": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
+      "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/istanbul-lib-report": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
+      "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "*"
+      }
+    },
+    "node_modules/@types/istanbul-reports": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
+      "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/istanbul-lib-report": "*"
+      }
+    },
+    "node_modules/@types/jest": {
+      "version": "29.5.14",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz",
+      "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "expect": "^29.0.0",
+        "pretty-format": "^29.0.0"
+      }
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "18.19.127",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.127.tgz",
+      "integrity": "sha512-gSjxjrnKXML/yo0BO099uPixMqfpJU0TKYjpfLU7TrtA2WWDki412Np/RSTPRil1saKBhvVVKzVx/p/6p94nVA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/@types/semver": {
+      "version": "7.7.1",
+      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
+      "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/stack-utils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
+      "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/yargs": {
+      "version": "17.0.33",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
+      "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/yargs-parser": "*"
+      }
+    },
+    "node_modules/@types/yargs-parser": {
+      "version": "21.0.3",
+      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
+      "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "5.62.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
+      "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.4.0",
+        "@typescript-eslint/scope-manager": "5.62.0",
+        "@typescript-eslint/type-utils": "5.62.0",
+        "@typescript-eslint/utils": "5.62.0",
+        "debug": "^4.3.4",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.2.0",
+        "natural-compare-lite": "^1.4.0",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^5.0.0",
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "5.62.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
+      "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "5.62.0",
+        "@typescript-eslint/types": "5.62.0",
+        "@typescript-eslint/typescript-estree": "5.62.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "5.62.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
+      "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "5.62.0",
+        "@typescript-eslint/visitor-keys": "5.62.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "5.62.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
+      "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/typescript-estree": "5.62.0",
+        "@typescript-eslint/utils": "5.62.0",
+        "debug": "^4.3.4",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "5.62.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
+      "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "5.62.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
+      "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "@typescript-eslint/types": "5.62.0",
+        "@typescript-eslint/visitor-keys": "5.62.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "5.62.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
+      "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@types/json-schema": "^7.0.9",
+        "@types/semver": "^7.3.12",
+        "@typescript-eslint/scope-manager": "5.62.0",
+        "@typescript-eslint/types": "5.62.0",
+        "@typescript-eslint/typescript-estree": "5.62.0",
+        "eslint-scope": "^5.1.1",
+        "semver": "^7.3.7"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "5.62.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
+      "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "5.62.0",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@ungap/structured-clone": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
+      "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/acorn": {
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+      "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-escapes": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+      "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "type-fest": "^0.21.3"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-escapes/node_modules/type-fest": {
+      "version": "0.21.3",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+      "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+      "dev": true,
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true,
+      "license": "Python-2.0"
+    },
+    "node_modules/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-jest": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
+      "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/transform": "^29.7.0",
+        "@types/babel__core": "^7.1.14",
+        "babel-plugin-istanbul": "^6.1.1",
+        "babel-preset-jest": "^29.6.3",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.8.0"
+      }
+    },
+    "node_modules/babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+      "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+      "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-plugin-istanbul/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/babel-plugin-jest-hoist": {
+      "version": "29.6.3",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
+      "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.3.3",
+        "@babel/types": "^7.3.3",
+        "@types/babel__core": "^7.1.14",
+        "@types/babel__traverse": "^7.0.6"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/babel-preset-current-node-syntax": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz",
+      "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-bigint": "^7.8.3",
+        "@babel/plugin-syntax-class-properties": "^7.12.13",
+        "@babel/plugin-syntax-class-static-block": "^7.14.5",
+        "@babel/plugin-syntax-import-attributes": "^7.24.7",
+        "@babel/plugin-syntax-import-meta": "^7.10.4",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.10.4",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
+        "@babel/plugin-syntax-top-level-await": "^7.14.5"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0 || ^8.0.0-0"
+      }
+    },
+    "node_modules/babel-preset-jest": {
+      "version": "29.6.3",
+      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
+      "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "babel-plugin-jest-hoist": "^29.6.3",
+        "babel-preset-current-node-syntax": "^1.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/baseline-browser-mapping": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.8.tgz",
+      "integrity": "sha512-be0PUaPsQX/gPWWgFsdD+GFzaoig5PXaUC1xLkQiYdDnANU8sMnHoQd8JhbJQuvTWrWLyeFN9Imb5Qtfvr4RrQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "baseline-browser-mapping": "dist/cli.js"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.26.2",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
+      "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "baseline-browser-mapping": "^2.8.3",
+        "caniuse-lite": "^1.0.30001741",
+        "electron-to-chromium": "^1.5.218",
+        "node-releases": "^2.0.21",
+        "update-browserslist-db": "^1.1.3"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/bs-logger": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+      "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-json-stable-stringify": "2.x"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/bser": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
+      "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "node-int64": "^0.4.0"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001745",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001745.tgz",
+      "integrity": "sha512-ywt6i8FzvdgrrrGbr1jZVObnVv6adj+0if2/omv9cmR2oiZs30zL4DIyaptKcbOrBdOIc74QTMoJvSE2QHh5UQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/char-regex": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+      "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ci-info": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
+      "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/sibiraj-s"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cjs-module-lexer": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
+      "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">= 1.0.0",
+        "node": ">= 0.12.0"
+      }
+    },
+    "node_modules/collect-v8-coverage": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
+      "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/create-jest": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
+      "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.6.3",
+        "chalk": "^4.0.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.9",
+        "jest-config": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "prompts": "^2.0.1"
+      },
+      "bin": {
+        "create-jest": "bin/create-jest.js"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/dedent": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz",
+      "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "babel-plugin-macros": "^3.1.0"
+      },
+      "peerDependenciesMeta": {
+        "babel-plugin-macros": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/deepmerge": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+      "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/detect-newline": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+      "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/diff-sequences": {
+      "version": "29.6.3",
+      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+      "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.226",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.226.tgz",
+      "integrity": "sha512-0tS/r72Ze0WUBiDwnqw4X43TxA7gEuZg0kFwLthoCzkshIbNQFjkf6D8xEzBe6tY6Y65fUhZIuNedTugw+11Lw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/emittery": {
+      "version": "0.13.1",
+      "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
+      "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/emittery?sponsor=1"
+      }
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+      "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "8.57.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+      "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+      "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.6.1",
+        "@eslint/eslintrc": "^2.1.4",
+        "@eslint/js": "8.57.1",
+        "@humanwhocodes/config-array": "^0.13.0",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@nodelib/fs.walk": "^1.2.8",
+        "@ungap/structured-clone": "^1.2.0",
+        "ajv": "^6.12.4",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.2.2",
+        "eslint-visitor-keys": "^3.4.3",
+        "espree": "^9.6.1",
+        "esquery": "^1.4.2",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "globals": "^13.19.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.2.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "is-path-inside": "^3.0.3",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.3",
+        "strip-ansi": "^6.0.1",
+        "text-table": "^0.2.0"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-config-prettier": {
+      "version": "8.10.2",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.2.tgz",
+      "integrity": "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "eslint-config-prettier": "bin/cli.js"
+      },
+      "peerDependencies": {
+        "eslint": ">=7.0.0"
+      }
+    },
+    "node_modules/eslint-plugin-prettier": {
+      "version": "4.2.5",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.5.tgz",
+      "integrity": "sha512-9Ni+xgemM2IWLq6aXEpP2+V/V30GeA/46Ar629vcMqVPodFFWC9skHu/D1phvuqtS8bJCFnNf01/qcmqYEwNfg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prettier-linter-helpers": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "eslint": ">=7.28.0",
+        "prettier": ">=2.0.0"
+      },
+      "peerDependenciesMeta": {
+        "eslint-config-prettier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^4.1.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint/node_modules/eslint-scope": {
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+      "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/espree": {
+      "version": "9.6.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "acorn": "^8.9.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.4.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+      "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "estraverse": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/esquery/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esrecurse/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/execa": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.0",
+        "human-signals": "^2.1.0",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.1",
+        "onetime": "^5.1.2",
+        "signal-exit": "^3.0.3",
+        "strip-final-newline": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/expect": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
+      "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/expect-utils": "^29.7.0",
+        "jest-get-type": "^29.6.3",
+        "jest-matcher-utils": "^29.7.0",
+        "jest-message-util": "^29.7.0",
+        "jest-util": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-diff": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+      "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
+      "dev": true,
+      "license": "Apache-2.0"
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.8"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fastq": {
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+      "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/fb-watchman": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+      "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "bser": "2.1.1"
+      }
+    },
+    "node_modules/file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flat-cache": "^3.0.4"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/flat-cache": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+      "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flatted": "^3.2.9",
+        "keyv": "^4.5.3",
+        "rimraf": "^3.0.2"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/flat-cache/node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "deprecated": "Rimraf versions prior to v4 are no longer supported",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+      "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/get-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "deprecated": "Glob versions prior to v9 are no longer supported",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/globals": {
+      "version": "13.24.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/handlebars": {
+      "version": "4.7.8",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
+      "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "minimist": "^1.2.5",
+        "neo-async": "^2.6.2",
+        "source-map": "^0.6.1",
+        "wordwrap": "^1.0.0"
+      },
+      "bin": {
+        "handlebars": "bin/handlebars"
+      },
+      "engines": {
+        "node": ">=0.4.7"
+      },
+      "optionalDependencies": {
+        "uglify-js": "^3.1.4"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/human-signals": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=10.17.0"
+      }
+    },
+    "node_modules/ignore": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+      "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/import-local": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
+      "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "pkg-dir": "^4.2.0",
+        "resolve-cwd": "^3.0.0"
+      },
+      "bin": {
+        "import-local-fixture": "fixtures/cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-core-module": {
+      "version": "2.16.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+      "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-generator-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+      "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-path-inside": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/istanbul-lib-coverage": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
+      "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
+      "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@babel/core": "^7.23.9",
+        "@babel/parser": "^7.23.9",
+        "@istanbuljs/schema": "^0.1.3",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^7.5.4"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-report": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+      "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^4.0.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-reports": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
+      "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
+      "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@jest/core": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "import-local": "^3.0.2",
+        "jest-cli": "^29.7.0"
+      },
+      "bin": {
+        "jest": "bin/jest.js"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-changed-files": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
+      "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "execa": "^5.0.0",
+        "jest-util": "^29.7.0",
+        "p-limit": "^3.1.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-circus": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz",
+      "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/environment": "^29.7.0",
+        "@jest/expect": "^29.7.0",
+        "@jest/test-result": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "co": "^4.6.0",
+        "dedent": "^1.0.0",
+        "is-generator-fn": "^2.0.0",
+        "jest-each": "^29.7.0",
+        "jest-matcher-utils": "^29.7.0",
+        "jest-message-util": "^29.7.0",
+        "jest-runtime": "^29.7.0",
+        "jest-snapshot": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "p-limit": "^3.1.0",
+        "pretty-format": "^29.7.0",
+        "pure-rand": "^6.0.0",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-cli": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz",
+      "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/core": "^29.7.0",
+        "@jest/test-result": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "chalk": "^4.0.0",
+        "create-jest": "^29.7.0",
+        "exit": "^0.1.2",
+        "import-local": "^3.0.2",
+        "jest-config": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "jest-validate": "^29.7.0",
+        "yargs": "^17.3.1"
+      },
+      "bin": {
+        "jest": "bin/jest.js"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-config": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz",
+      "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.11.6",
+        "@jest/test-sequencer": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "babel-jest": "^29.7.0",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "deepmerge": "^4.2.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "jest-circus": "^29.7.0",
+        "jest-environment-node": "^29.7.0",
+        "jest-get-type": "^29.6.3",
+        "jest-regex-util": "^29.6.3",
+        "jest-resolve": "^29.7.0",
+        "jest-runner": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "jest-validate": "^29.7.0",
+        "micromatch": "^4.0.4",
+        "parse-json": "^5.2.0",
+        "pretty-format": "^29.7.0",
+        "slash": "^3.0.0",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@types/node": "*",
+        "ts-node": ">=9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "ts-node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-diff": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
+      "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "diff-sequences": "^29.6.3",
+        "jest-get-type": "^29.6.3",
+        "pretty-format": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-docblock": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz",
+      "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "detect-newline": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-each": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz",
+      "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.6.3",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^29.6.3",
+        "jest-util": "^29.7.0",
+        "pretty-format": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-environment-node": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
+      "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/environment": "^29.7.0",
+        "@jest/fake-timers": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "jest-mock": "^29.7.0",
+        "jest-util": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-get-type": {
+      "version": "29.6.3",
+      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
+      "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-haste-map": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
+      "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.6.3",
+        "@types/graceful-fs": "^4.1.3",
+        "@types/node": "*",
+        "anymatch": "^3.0.3",
+        "fb-watchman": "^2.0.0",
+        "graceful-fs": "^4.2.9",
+        "jest-regex-util": "^29.6.3",
+        "jest-util": "^29.7.0",
+        "jest-worker": "^29.7.0",
+        "micromatch": "^4.0.4",
+        "walker": "^1.0.8"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "^2.3.2"
+      }
+    },
+    "node_modules/jest-leak-detector": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
+      "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jest-get-type": "^29.6.3",
+        "pretty-format": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-matcher-utils": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
+      "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "jest-diff": "^29.7.0",
+        "jest-get-type": "^29.6.3",
+        "pretty-format": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-message-util": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
+      "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.12.13",
+        "@jest/types": "^29.6.3",
+        "@types/stack-utils": "^2.0.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "micromatch": "^4.0.4",
+        "pretty-format": "^29.7.0",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-mock": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
+      "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "jest-util": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-pnp-resolver": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
+      "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      },
+      "peerDependencies": {
+        "jest-resolve": "*"
+      },
+      "peerDependenciesMeta": {
+        "jest-resolve": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-regex-util": {
+      "version": "29.6.3",
+      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
+      "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-resolve": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz",
+      "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.7.0",
+        "jest-pnp-resolver": "^1.2.2",
+        "jest-util": "^29.7.0",
+        "jest-validate": "^29.7.0",
+        "resolve": "^1.20.0",
+        "resolve.exports": "^2.0.0",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-resolve-dependencies": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
+      "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jest-regex-util": "^29.6.3",
+        "jest-snapshot": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-runner": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz",
+      "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/console": "^29.7.0",
+        "@jest/environment": "^29.7.0",
+        "@jest/test-result": "^29.7.0",
+        "@jest/transform": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "emittery": "^0.13.1",
+        "graceful-fs": "^4.2.9",
+        "jest-docblock": "^29.7.0",
+        "jest-environment-node": "^29.7.0",
+        "jest-haste-map": "^29.7.0",
+        "jest-leak-detector": "^29.7.0",
+        "jest-message-util": "^29.7.0",
+        "jest-resolve": "^29.7.0",
+        "jest-runtime": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "jest-watcher": "^29.7.0",
+        "jest-worker": "^29.7.0",
+        "p-limit": "^3.1.0",
+        "source-map-support": "0.5.13"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-runtime": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz",
+      "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/environment": "^29.7.0",
+        "@jest/fake-timers": "^29.7.0",
+        "@jest/globals": "^29.7.0",
+        "@jest/source-map": "^29.6.3",
+        "@jest/test-result": "^29.7.0",
+        "@jest/transform": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "cjs-module-lexer": "^1.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.7.0",
+        "jest-message-util": "^29.7.0",
+        "jest-mock": "^29.7.0",
+        "jest-regex-util": "^29.6.3",
+        "jest-resolve": "^29.7.0",
+        "jest-snapshot": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "slash": "^3.0.0",
+        "strip-bom": "^4.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-snapshot": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
+      "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.11.6",
+        "@babel/generator": "^7.7.2",
+        "@babel/plugin-syntax-jsx": "^7.7.2",
+        "@babel/plugin-syntax-typescript": "^7.7.2",
+        "@babel/types": "^7.3.3",
+        "@jest/expect-utils": "^29.7.0",
+        "@jest/transform": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "babel-preset-current-node-syntax": "^1.0.0",
+        "chalk": "^4.0.0",
+        "expect": "^29.7.0",
+        "graceful-fs": "^4.2.9",
+        "jest-diff": "^29.7.0",
+        "jest-get-type": "^29.6.3",
+        "jest-matcher-utils": "^29.7.0",
+        "jest-message-util": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "natural-compare": "^1.4.0",
+        "pretty-format": "^29.7.0",
+        "semver": "^7.5.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-util": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
+      "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "graceful-fs": "^4.2.9",
+        "picomatch": "^2.2.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-validate": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz",
+      "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/types": "^29.6.3",
+        "camelcase": "^6.2.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^29.6.3",
+        "leven": "^3.1.0",
+        "pretty-format": "^29.7.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-validate/node_modules/camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/jest-watcher": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz",
+      "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/test-result": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "emittery": "^0.13.1",
+        "jest-util": "^29.7.0",
+        "string-length": "^4.0.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-worker": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
+      "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*",
+        "jest-util": "^29.7.0",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^8.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-worker/node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+      "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "json-buffer": "3.0.1"
+      }
+    },
+    "node_modules/kleur": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+      "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash.memoize": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+      "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/make-dir": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+      "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "semver": "^7.5.3"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/makeerror": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
+      "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "tmpl": "1.0.5"
+      }
+    },
+    "node_modules/merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "4.2.8",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
+      "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/natural-compare-lite": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+      "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/neo-async": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+      "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/node-int64": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+      "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.21",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz",
+      "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/npm-run-path": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/onetime": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mimic-fn": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/optionator": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.5"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/path-scurry": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+      "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "lru-cache": "^10.2.0",
+        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/path-scurry/node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/path-scurry/node_modules/minipass": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pirates": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
+      "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "find-up": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
+    "node_modules/prettier-linter-helpers": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+      "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-diff": "^1.1.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/pretty-format": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+      "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jest/schemas": "^29.6.3",
+        "ansi-styles": "^5.0.0",
+        "react-is": "^18.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/pretty-format/node_modules/ansi-styles": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+      "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/prompts": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+      "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "kleur": "^3.0.3",
+        "sisteransi": "^1.0.5"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/pure-rand": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
+      "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/dubzzz"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/fast-check"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/react-is": {
+      "version": "18.3.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+      "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "1.22.10",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+      "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.16.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-cwd": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+      "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve-cwd/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/resolve.exports": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz",
+      "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz",
+      "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "glob": "^9.2.0"
+      },
+      "bin": {
+        "rimraf": "dist/cjs/src/bin.js"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/rimraf/node_modules/brace-expansion": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+      "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/rimraf/node_modules/glob": {
+      "version": "9.3.5",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
+      "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "minimatch": "^8.0.2",
+        "minipass": "^4.2.4",
+        "path-scurry": "^1.6.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/rimraf/node_modules/minimatch": {
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz",
+      "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+      "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/sisteransi": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+      "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.13",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
+      "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/stack-utils": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+      "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "escape-string-regexp": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/stack-utils/node_modules/escape-string-regexp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+      "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-length": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
+      "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "char-regex": "^1.0.2",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-bom": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-final-newline": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tmpl": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+      "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/ts-jest": {
+      "version": "29.4.4",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.4.tgz",
+      "integrity": "sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bs-logger": "^0.2.6",
+        "fast-json-stable-stringify": "^2.1.0",
+        "handlebars": "^4.7.8",
+        "json5": "^2.2.3",
+        "lodash.memoize": "^4.1.2",
+        "make-error": "^1.3.6",
+        "semver": "^7.7.2",
+        "type-fest": "^4.41.0",
+        "yargs-parser": "^21.1.1"
+      },
+      "bin": {
+        "ts-jest": "cli.js"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": ">=7.0.0-beta.0 <8",
+        "@jest/transform": "^29.0.0 || ^30.0.0",
+        "@jest/types": "^29.0.0 || ^30.0.0",
+        "babel-jest": "^29.0.0 || ^30.0.0",
+        "jest": "^29.0.0 || ^30.0.0",
+        "jest-util": "^29.0.0 || ^30.0.0",
+        "typescript": ">=4.3 <6"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        },
+        "@jest/transform": {
+          "optional": true
+        },
+        "@jest/types": {
+          "optional": true
+        },
+        "babel-jest": {
+          "optional": true
+        },
+        "esbuild": {
+          "optional": true
+        },
+        "jest-util": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/ts-jest/node_modules/type-fest": {
+      "version": "4.41.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+      "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+      "dev": true,
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true,
+      "license": "0BSD"
+    },
+    "node_modules/tsutils": {
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^1.8.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+      }
+    },
+    "node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/type-detect": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.9.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
+      "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/uglify-js": {
+      "version": "3.19.3",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
+      "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "optional": true,
+      "bin": {
+        "uglifyjs": "bin/uglifyjs"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+      "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/v8-to-istanbul": {
+      "version": "9.3.0",
+      "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
+      "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.12",
+        "@types/istanbul-lib-coverage": "^2.0.1",
+        "convert-source-map": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10.12.0"
+      }
+    },
+    "node_modules/walker": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+      "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "makeerror": "1.0.12"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/write-file-atomic": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
+      "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "imurmurhash": "^0.1.4",
+        "signal-exit": "^3.0.7"
+      },
+      "engines": {
+        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/yargs": {
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    }
+  }
+}

+ 11 - 0
libs/credential-manager/test_simple.mjs

@@ -0,0 +1,11 @@
+import { CredentialManagerFactory } from './dist/index.js';
+
+console.log('Testing credential manager...');
+
+try {
+  const manager = CredentialManagerFactory.createCredentialManager();
+  console.log('✅ CredentialManager created successfully');
+  console.log('✅ All TypeScript compilation and exports working');
+} catch (error) {
+  console.error('❌ Error:', error.message);
+}

+ 0 - 873
src/core/accounts/manager.ts

@@ -1,873 +0,0 @@
-/**
- * 🏦 统一账户管理器 v2.0 - Delta中性控制平面账户管理核心
- *
- * 基于tasks规范重构的统一账户管理器,支持:
- * - Delta中性控制平面账户模型集成
- * - 多平台多账户统一管理(Pacifica、Aster、Binance)
- * - 企业级风险包络集成
- * - 多平台认证策略支持
- * - 资金利用率目标管理(50%-80%)
- * - 实时状态同步和账户健康监控
- * - WebSocket + HTTP双模式数据更新
- */
-
-import { EventEmitter } from 'events'
-import { ExchangeAccount, ExchangeAccountConfig, AccountMetrics, DeltaControlParams } from './ExchangeAccount'
-import { RiskEnvelope, RiskEnvelopeConfig } from './RiskEnvelope'
-import { TradingService, ServiceStatus, AccountState } from '../shared/types/index'
-import { logger } from '../shared/utils/logger'
-
-/**
- * 多平台账户配置
- */
-export interface UnifiedAccountConfig extends ExchangeAccountConfig {
-  // 账户元信息
-  alias?: string // 显示别名
-  enabled: boolean // 是否启用
-  priority: number // 优先级 (1-10)
-
-  // 交易和对冲控制
-  tradingEnabled: boolean // 是否允许交易
-  hedgingEnabled: boolean // 是否允许参与对冲
-
-  // 风险控制参数
-  maxDailyVolumeUsd: number // 最大日交易量
-  emergencyContactInfo?: string // 紧急联系信息
-
-  // 平台特定配置
-  proxySessionId?: string // 代理会话ID
-  authenticationMethod: 'ed25519' | 'eip191' | 'hmac' // 认证方法
-  requiresProxy: boolean // 是否需要代理
-  sessionManagement: boolean // 是否需要会话管理
-}
-
-/**
- * 账户摘要信息
- */
-export interface AccountSummary {
-  accountId: string
-  exchange: 'pacifica' | 'aster' | 'binance'
-  alias?: string
-  status: 'active' | 'paused' | 'emergency' | 'offline' | 'error'
-
-  // 财务指标
-  metrics: AccountMetrics
-  deltaParams: DeltaControlParams
-
-  // 实时状态
-  isOnline: boolean
-  lastHeartbeat: Date
-  lastTradeTime?: Date
-  connectionQuality: 'excellent' | 'good' | 'poor' | 'disconnected'
-
-  // 风险状态
-  riskEnvelopeId?: string
-  riskViolations: number
-  emergencyMode: boolean
-
-  // 配置信息
-  config: UnifiedAccountConfig
-
-  // 性能指标
-  totalEquityUsd: number
-  dailyVolumeUsd: number
-  openOrdersCount: number
-  lastUpdateTime: Date
-
-  // 错误信息
-  errors: string[]
-  warnings: string[]
-}
-
-/**
- * 对冲组配置
- */
-export interface HedgingGroup {
-  groupId: string
-  name: string
-  strategy: 'delta-neutral' | 'cross-platform-arbitrage' | 'funding-rate-arbitrage'
-  accounts: string[] // 参与账户ID列表
-  maxExposureUsd: number // 最大敞口
-  targetUtilization: number // 目标利用率
-  enabled: boolean
-  priority: number
-  createdAt: Date
-  lastRebalance?: Date
-}
-
-/**
- * 账户性能指标
- */
-export interface AccountPerformanceMetrics {
-  accountId: string
-
-  // Delta中性指标
-  avgDeltaDeviation: number // 平均Delta偏差
-  deltaViolationCount: number // Delta违规次数
-  maxDeltaDeviation: number // 最大Delta偏差
-  deltaControlEfficiency: number // Delta控制效率 (0-1)
-
-  // 利用率指标
-  avgUtilization: number // 平均利用率
-  utilizationStability: number // 利用率稳定性
-  targetUtilizationHitRate: number // 目标利用率命中率
-
-  // 交易指标
-  totalTrades: number // 总交易数
-  successfulTrades: number // 成功交易数
-  avgExecutionTime: number // 平均执行时间
-
-  // 风险指标
-  maxDrawdown: number // 最大回撤
-  sharpeRatio: number // 夏普比率
-  riskAdjustedReturn: number // 风险调整收益
-
-  // 时间范围
-  periodStart: Date
-  periodEnd: Date
-}
-
-/**
- * 统一账户管理器
- */
-export class UnifiedAccountManager extends EventEmitter implements TradingService {
-  private status: 'stopped' | 'initializing' | 'running' | 'stopping' | 'error' = 'stopped'
-  private lastStatusChange = Date.now()
-
-  // 核心存储
-  private accounts: Map<string, ExchangeAccount> = new Map()
-  private accountConfigs: Map<string, UnifiedAccountConfig> = new Map()
-  private hedgingGroups: Map<string, HedgingGroup> = new Map()
-  private performanceMetrics: Map<string, AccountPerformanceMetrics> = new Map()
-
-  // 运行时状态
-  private updateIntervals: Map<string, NodeJS.Timeout> = new Map()
-  private connectionHealthChecks: Map<string, NodeJS.Timeout> = new Map()
-  private lastAccountUpdates: Map<string, Date> = new Map()
-
-  // 配置参数
-  private readonly config = {
-    accountUpdateInterval: 30000, // 30秒账户状态更新
-    healthCheckInterval: 10000, // 10秒健康检查
-    performanceReportInterval: 300000, // 5分钟性能报告
-    maxAccountsPerGroup: 10, // 每组最大账户数
-    deltaThreshold: 0.0005, // 全局Delta阈值
-    utilizationTargetMin: 0.5, // 50%最小利用率
-    utilizationTargetMax: 0.8, // 80%最大利用率
-    emergencyResponseTime: 5000, // 5秒紧急响应时间
-  }
-
-  constructor() {
-    super()
-    this.setupEventHandlers()
-  }
-
-  /**
-   * 初始化统一账户管理器
-   */
-  async initialize(): Promise<void> {
-    logger.info('🏦 UnifiedAccountManager v2.0 初始化开始')
-    this.status = 'initializing'
-    this.lastStatusChange = Date.now()
-
-    try {
-      // 1. 验证系统配置
-      await this.validateSystemConfiguration()
-
-      // 2. 初始化所有注册账户
-      await this.initializeRegisteredAccounts()
-
-      // 3. 设置监控和健康检查
-      this.setupMonitoringAndHealthChecks()
-
-      this.status = 'running'
-      this.lastStatusChange = Date.now()
-
-      logger.info('✅ UnifiedAccountManager v2.0 初始化完成')
-      logger.info(`📊 管理账户数: ${this.accounts.size}`)
-      logger.info(`🔗 对冲组数: ${this.hedgingGroups.size}`)
-      logger.info(`🎯 Delta阈值: ±${this.config.deltaThreshold} BTC`)
-      logger.info(`📈 利用率目标: ${this.config.utilizationTargetMin * 100}-${this.config.utilizationTargetMax * 100}%`)
-    } catch (error) {
-      this.status = 'error'
-      this.lastStatusChange = Date.now()
-      logger.error('❌ UnifiedAccountManager 初始化失败:', error)
-      throw error
-    }
-  }
-
-  /**
-   * 启动统一账户管理器
-   */
-  async start(): Promise<void> {
-    if (this.status !== 'running') {
-      throw new Error('UnifiedAccountManager 必须先完成初始化')
-    }
-
-    logger.info('🚀 UnifiedAccountManager v2.0 启动中')
-
-    try {
-      // 1. 启动所有账户的定期更新
-      this.startAccountUpdates()
-
-      // 2. 启动健康检查
-      this.startHealthChecks()
-
-      // 3. 启动性能监控
-      this.startPerformanceMonitoring()
-
-      // 4. 执行初始状态同步
-      await this.performInitialStateSynchronization()
-
-      logger.info('✅ UnifiedAccountManager v2.0 启动完成')
-      logger.info(`🔄 账户更新间隔: ${this.config.accountUpdateInterval}ms`)
-      logger.info(`💚 健康检查间隔: ${this.config.healthCheckInterval}ms`)
-      logger.info(`📊 性能报告间隔: ${this.config.performanceReportInterval}ms`)
-
-      this.emit('manager-started', {
-        timestamp: new Date(),
-        accountCount: this.accounts.size,
-        hedgingGroupCount: this.hedgingGroups.size,
-      })
-    } catch (error) {
-      this.status = 'error'
-      this.lastStatusChange = Date.now()
-      logger.error('❌ UnifiedAccountManager 启动失败:', error)
-      throw error
-    }
-  }
-
-  /**
-   * 停止统一账户管理器
-   */
-  async stop(): Promise<void> {
-    logger.info('🛑 UnifiedAccountManager v2.0 停止中')
-    this.status = 'stopping'
-    this.lastStatusChange = Date.now()
-
-    try {
-      // 1. 停止所有定时器
-      this.stopAllTimers()
-
-      // 2. 执行优雅关闭
-      await this.performGracefulShutdown()
-
-      // 3. 清理资源
-      this.cleanup()
-
-      this.status = 'stopped'
-      this.lastStatusChange = Date.now()
-
-      logger.info('✅ UnifiedAccountManager v2.0 已安全停止')
-
-      this.emit('manager-stopped', {
-        timestamp: new Date(),
-        finalAccountCount: this.accounts.size,
-      })
-    } catch (error) {
-      this.status = 'error'
-      this.lastStatusChange = Date.now()
-      logger.error('❌ UnifiedAccountManager 停止失败:', error)
-      throw error
-    }
-  }
-
-  /**
-   * 添加账户
-   */
-  async addAccount(config: UnifiedAccountConfig): Promise<void> {
-    logger.info(`📝 添加账户: ${config.accountId} (${config.exchange})`)
-
-    try {
-      // 1. 验证账户配置
-      this.validateAccountConfig(config)
-
-      // 2. 检查重复
-      if (this.accounts.has(config.accountId)) {
-        throw new Error(`账户 ${config.accountId} 已存在`)
-      }
-
-      // 3. 创建ExchangeAccount实例
-      const exchangeAccountConfig: ExchangeAccountConfig = {
-        accountId: config.accountId,
-        exchange: config.exchange,
-        accountName: config.alias || config.accountId,
-        publicKey: config.publicKey,
-        privateKey: config.privateKey,
-        proxyProfile: config.proxyProfile,
-        utilizationTargetMin: config.utilizationTargetMin,
-        utilizationTargetMax: config.utilizationTargetMax,
-        deltaThreshold: config.deltaThreshold,
-        maxPositionValue: config.maxPositionValue,
-        stopLossConfigId: `stop-loss-${config.accountId}`,
-        status: config.enabled ? 'active' : 'paused',
-      }
-
-      const account = new ExchangeAccount(exchangeAccountConfig)
-
-      // 4. 存储账户和配置
-      this.accounts.set(config.accountId, account)
-      this.accountConfigs.set(config.accountId, config)
-
-      // 5. 初始化性能指标
-      this.initializeAccountPerformanceMetrics(config.accountId)
-
-      // 6. 如果管理器正在运行,立即启动此账户的监控
-      if (this.status === 'running') {
-        this.startAccountMonitoring(config.accountId)
-      }
-
-      logger.info(`✅ 账户 ${config.accountId} 添加成功`)
-
-      this.emit('account-added', {
-        accountId: config.accountId,
-        exchange: config.exchange,
-        timestamp: new Date(),
-      })
-    } catch (error) {
-      logger.error(`❌ 添加账户 ${config.accountId} 失败:`, error)
-      throw error
-    }
-  }
-
-  /**
-   * 移除账户
-   */
-  async removeAccount(accountId: string): Promise<void> {
-    logger.info(`🗑️ 移除账户: ${accountId}`)
-
-    try {
-      const account = this.accounts.get(accountId)
-      if (!account) {
-        throw new Error(`账户 ${accountId} 不存在`)
-      }
-
-      // 1. 检查是否在对冲组中
-      const hedgingGroupsWithAccount = Array.from(this.hedgingGroups.values()).filter(group =>
-        group.accounts.includes(accountId),
-      )
-
-      if (hedgingGroupsWithAccount.length > 0) {
-        logger.warn(`⚠️ 账户 ${accountId} 属于 ${hedgingGroupsWithAccount.length} 个对冲组,将从所有组中移除`)
-
-        for (const group of hedgingGroupsWithAccount) {
-          await this.removeAccountFromHedgingGroup(group.groupId, accountId)
-        }
-      }
-
-      // 2. 停止监控
-      this.stopAccountMonitoring(accountId)
-
-      // 3. 清理数据
-      this.accounts.delete(accountId)
-      this.accountConfigs.delete(accountId)
-      this.performanceMetrics.delete(accountId)
-      this.lastAccountUpdates.delete(accountId)
-
-      logger.info(`✅ 账户 ${accountId} 移除成功`)
-
-      this.emit('account-removed', {
-        accountId,
-        timestamp: new Date(),
-      })
-    } catch (error) {
-      logger.error(`❌ 移除账户 ${accountId} 失败:`, error)
-      throw error
-    }
-  }
-
-  /**
-   * 获取账户
-   */
-  getAccount(accountId: string): ExchangeAccount | undefined {
-    return this.accounts.get(accountId)
-  }
-
-  /**
-   * 获取所有账户
-   */
-  getAllAccounts(): ExchangeAccount[] {
-    return Array.from(this.accounts.values())
-  }
-
-  /**
-   * 获取活跃账户
-   */
-  getActiveAccounts(): ExchangeAccount[] {
-    return this.getAllAccounts().filter(account => account.getConfig().status === 'active')
-  }
-
-  /**
-   * 获取需要对冲的账户
-   */
-  getAccountsNeedingHedge(): ExchangeAccount[] {
-    return this.getAllAccounts().filter(account => account.needsEmergencyHedge() || account.needsRebalance())
-  }
-
-  /**
-   * 获取账户摘要
-   */
-  getAccountSummary(accountId: string): AccountSummary | undefined {
-    const account = this.accounts.get(accountId)
-    const config = this.accountConfigs.get(accountId)
-
-    if (!account || !config) {
-      return undefined
-    }
-
-    const lastUpdate = this.lastAccountUpdates.get(accountId) || new Date(0)
-    const timeSinceUpdate = Date.now() - lastUpdate.getTime()
-
-    // 确定连接质量
-    let connectionQuality: 'excellent' | 'good' | 'poor' | 'disconnected' = 'disconnected'
-    if (timeSinceUpdate < 30000) connectionQuality = 'excellent'
-    else if (timeSinceUpdate < 60000) connectionQuality = 'good'
-    else if (timeSinceUpdate < 180000) connectionQuality = 'poor'
-
-    const summary: AccountSummary = {
-      accountId: account.getConfig().accountId,
-      exchange: account.getConfig().exchange,
-      alias: config.alias,
-      status: account.getConfig().status,
-
-      metrics: account.getMetrics(),
-      deltaParams: account.getDeltaParams(),
-
-      isOnline: connectionQuality !== 'disconnected',
-      lastHeartbeat: lastUpdate,
-      connectionQuality,
-
-      riskEnvelopeId: config.stopLossConfigId,
-      riskViolations: 0, // 需要从RiskEnvelope获取
-      emergencyMode: account.getConfig().status === 'emergency',
-
-      config,
-
-      totalEquityUsd: account.getMetrics().totalBalance,
-      dailyVolumeUsd: 0, // 需要计算
-      openOrdersCount: 0, // 需要获取
-      lastUpdateTime: lastUpdate,
-
-      errors: [],
-      warnings: [],
-    }
-
-    // 添加警告信息
-    if (account.needsEmergencyHedge()) {
-      summary.warnings.push('需要紧急对冲')
-    }
-    if (account.needsRebalance()) {
-      summary.warnings.push('需要利用率再平衡')
-    }
-
-    return summary
-  }
-
-  /**
-   * 获取所有账户摘要
-   */
-  getAllAccountSummaries(): AccountSummary[] {
-    return Array.from(this.accounts.keys())
-      .map(accountId => this.getAccountSummary(accountId))
-      .filter(summary => summary !== undefined) as AccountSummary[]
-  }
-
-  /**
-   * 计算全局Delta
-   */
-  calculateGlobalDelta(): number {
-    return this.getAllAccounts().reduce((total, account) => {
-      return total + account.getMetrics().currentDelta
-    }, 0)
-  }
-
-  /**
-   * 计算全局利用率
-   */
-  calculateGlobalUtilization(): number {
-    const accounts = this.getAllAccounts()
-    if (accounts.length === 0) return 0
-
-    let totalValue = 0
-    let totalBalance = 0
-
-    accounts.forEach(account => {
-      const metrics = account.getMetrics()
-      totalValue += Math.abs(metrics.netPosition) * 65000 // 假设BTC价格
-      totalBalance += metrics.totalBalance
-    })
-
-    return totalBalance > 0 ? totalValue / totalBalance : 0
-  }
-
-  /**
-   * 获取系统状态摘要
-   */
-  getSystemSummary() {
-    const accounts = this.getAllAccounts()
-    const activeAccounts = this.getActiveAccounts()
-    const needHedgeAccounts = this.getAccountsNeedingHedge()
-
-    return {
-      totalAccounts: accounts.length,
-      activeAccounts: activeAccounts.length,
-      accountsNeedingHedge: needHedgeAccounts.length,
-      globalDelta: this.calculateGlobalDelta(),
-      globalUtilization: this.calculateGlobalUtilization(),
-      hedgingGroups: this.hedgingGroups.size,
-      accounts: accounts.map(account => account.getStatusSummary()),
-      lastUpdate: new Date(),
-    }
-  }
-
-  /**
-   * 获取服务状态
-   */
-  getStatus(): ServiceStatus {
-    return {
-      name: 'UnifiedAccountManager',
-      status: this.status === 'running' ? 'running' : this.status === 'error' ? 'error' : 'stopped',
-      lastUpdate: this.lastStatusChange,
-      details: {
-        accountCount: this.accounts.size,
-        activeAccounts: this.getActiveAccounts().length,
-        hedgingGroups: this.hedgingGroups.size,
-        globalDelta: this.calculateGlobalDelta(),
-        globalUtilization: this.calculateGlobalUtilization(),
-      },
-    }
-  }
-
-  getLastStatusChange(): number {
-    return this.lastStatusChange
-  }
-
-  // ========== 私有方法 ==========
-
-  /**
-   * 设置事件处理器
-   */
-  private setupEventHandlers(): void {
-    this.on('account-delta-violation', data => {
-      logger.warn(`🚨 账户 ${data.accountId} Delta违规: ${data.delta}`)
-    })
-
-    this.on('account-utilization-violation', data => {
-      logger.warn(`⚠️ 账户 ${data.accountId} 利用率违规: ${data.utilization}`)
-    })
-
-    this.on('account-emergency', data => {
-      logger.error(`🆘 账户 ${data.accountId} 进入紧急状态: ${data.reason}`)
-    })
-  }
-
-  /**
-   * 验证系统配置
-   */
-  private async validateSystemConfiguration(): Promise<void> {
-    // 验证配置参数
-    if (this.config.deltaThreshold <= 0) {
-      throw new Error('Delta阈值必须大于0')
-    }
-
-    if (this.config.utilizationTargetMin >= this.config.utilizationTargetMax) {
-      throw new Error('最小利用率必须小于最大利用率')
-    }
-
-    logger.info('✅ 系统配置验证通过')
-  }
-
-  /**
-   * 初始化已注册账户
-   */
-  private async initializeRegisteredAccounts(): Promise<void> {
-    // 这里可以从配置文件或环境变量加载账户
-    logger.info('📋 初始化已注册账户完成')
-  }
-
-  /**
-   * 设置监控和健康检查
-   */
-  private setupMonitoringAndHealthChecks(): void {
-    logger.info('🔧 设置监控和健康检查完成')
-  }
-
-  /**
-   * 验证账户配置
-   */
-  private validateAccountConfig(config: UnifiedAccountConfig): void {
-    if (!config.accountId) {
-      throw new Error('accountId 是必需的')
-    }
-
-    if (!config.exchange) {
-      throw new Error('exchange 是必需的')
-    }
-
-    if (!['pacifica', 'aster', 'binance'].includes(config.exchange)) {
-      throw new Error('不支持的交易所')
-    }
-
-    if (!config.publicKey || !config.privateKey) {
-      throw new Error('publicKey 和 privateKey 是必需的')
-    }
-
-    if (config.utilizationTargetMin >= config.utilizationTargetMax) {
-      throw new Error('utilizationTargetMin 必须小于 utilizationTargetMax')
-    }
-
-    if (config.deltaThreshold <= 0) {
-      throw new Error('deltaThreshold 必须大于0')
-    }
-  }
-
-  /**
-   * 初始化账户性能指标
-   */
-  private initializeAccountPerformanceMetrics(accountId: string): void {
-    const metrics: AccountPerformanceMetrics = {
-      accountId,
-      avgDeltaDeviation: 0,
-      deltaViolationCount: 0,
-      maxDeltaDeviation: 0,
-      deltaControlEfficiency: 1,
-      avgUtilization: 0.65,
-      utilizationStability: 1,
-      targetUtilizationHitRate: 1,
-      totalTrades: 0,
-      successfulTrades: 0,
-      avgExecutionTime: 0,
-      maxDrawdown: 0,
-      sharpeRatio: 0,
-      riskAdjustedReturn: 0,
-      periodStart: new Date(),
-      periodEnd: new Date(),
-    }
-
-    this.performanceMetrics.set(accountId, metrics)
-  }
-
-  /**
-   * 启动账户更新
-   */
-  private startAccountUpdates(): void {
-    for (const accountId of this.accounts.keys()) {
-      this.startAccountMonitoring(accountId)
-    }
-  }
-
-  /**
-   * 启动单个账户监控
-   */
-  private startAccountMonitoring(accountId: string): void {
-    const interval = setInterval(async () => {
-      try {
-        await this.updateAccountState(accountId)
-      } catch (error) {
-        logger.error(`账户 ${accountId} 状态更新失败:`, error)
-      }
-    }, this.config.accountUpdateInterval)
-
-    this.updateIntervals.set(accountId, interval)
-  }
-
-  /**
-   * 停止账户监控
-   */
-  private stopAccountMonitoring(accountId: string): void {
-    const interval = this.updateIntervals.get(accountId)
-    if (interval) {
-      clearInterval(interval)
-      this.updateIntervals.delete(accountId)
-    }
-
-    const healthCheck = this.connectionHealthChecks.get(accountId)
-    if (healthCheck) {
-      clearInterval(healthCheck)
-      this.connectionHealthChecks.delete(accountId)
-    }
-  }
-
-  /**
-   * 更新账户状态
-   */
-  private async updateAccountState(accountId: string): Promise<void> {
-    const account = this.accounts.get(accountId)
-    if (!account) return
-
-    try {
-      // 模拟状态更新(实际实现需要调用交易所API)
-      const simulatedMetrics = {
-        currentUtilization: 0.65 + (Math.random() - 0.5) * 0.1,
-        currentDelta: (Math.random() - 0.5) * 0.002,
-        netPosition: (Math.random() - 0.5) * 0.1,
-        totalBalance: 1000 + Math.random() * 100,
-        availableBalance: 800 + Math.random() * 100,
-        unrealizedPnl: (Math.random() - 0.5) * 50,
-        leverage: 1 + Math.random() * 2,
-        lastUpdate: new Date(),
-      }
-
-      account.updateMetrics(simulatedMetrics)
-      this.lastAccountUpdates.set(accountId, new Date())
-
-      // 检查违规情况
-      this.checkAccountViolations(account)
-    } catch (error) {
-      logger.error(`更新账户 ${accountId} 状态失败:`, error)
-    }
-  }
-
-  /**
-   * 检查账户违规
-   */
-  private checkAccountViolations(account: ExchangeAccount): void {
-    const config = account.getConfig()
-    const metrics = account.getMetrics()
-
-    // 检查Delta违规
-    if (account.needsEmergencyHedge()) {
-      this.emit('account-delta-violation', {
-        accountId: config.accountId,
-        delta: metrics.currentDelta,
-        threshold: account.getDeltaParams().emergencyThreshold,
-      })
-    }
-
-    // 检查利用率违规
-    if (account.needsRebalance()) {
-      this.emit('account-utilization-violation', {
-        accountId: config.accountId,
-        utilization: metrics.currentUtilization,
-        targetMin: config.utilizationTargetMin,
-        targetMax: config.utilizationTargetMax,
-      })
-    }
-
-    // 检查紧急状态
-    if (config.status === 'emergency') {
-      this.emit('account-emergency', {
-        accountId: config.accountId,
-        reason: '账户处于紧急状态',
-      })
-    }
-  }
-
-  /**
-   * 启动健康检查
-   */
-  private startHealthChecks(): void {
-    for (const accountId of this.accounts.keys()) {
-      const interval = setInterval(() => {
-        this.performAccountHealthCheck(accountId)
-      }, this.config.healthCheckInterval)
-
-      this.connectionHealthChecks.set(accountId, interval)
-    }
-  }
-
-  /**
-   * 执行账户健康检查
-   */
-  private performAccountHealthCheck(accountId: string): void {
-    const lastUpdate = this.lastAccountUpdates.get(accountId)
-    if (!lastUpdate) return
-
-    const timeSinceUpdate = Date.now() - lastUpdate.getTime()
-
-    if (timeSinceUpdate > this.config.accountUpdateInterval * 3) {
-      logger.warn(`⚠️ 账户 ${accountId} 健康检查失败,上次更新: ${Math.round(timeSinceUpdate / 1000)}秒前`)
-    }
-  }
-
-  /**
-   * 启动性能监控
-   */
-  private startPerformanceMonitoring(): void {
-    setInterval(() => {
-      this.generatePerformanceReport()
-    }, this.config.performanceReportInterval)
-  }
-
-  /**
-   * 生成性能报告
-   */
-  private generatePerformanceReport(): void {
-    const summary = this.getSystemSummary()
-
-    logger.info('📊 UnifiedAccountManager 性能报告', {
-      accounts: summary.totalAccounts,
-      active: summary.activeAccounts,
-      needingHedge: summary.accountsNeedingHedge,
-      globalDelta: summary.globalDelta.toFixed(6),
-      globalUtilization: (summary.globalUtilization * 100).toFixed(1) + '%',
-      hedgingGroups: summary.hedgingGroups,
-    })
-  }
-
-  /**
-   * 执行初始状态同步
-   */
-  private async performInitialStateSynchronization(): Promise<void> {
-    logger.info('🔄 执行初始状态同步')
-
-    for (const accountId of this.accounts.keys()) {
-      try {
-        await this.updateAccountState(accountId)
-      } catch (error) {
-        logger.error(`初始同步账户 ${accountId} 失败:`, error)
-      }
-    }
-  }
-
-  /**
-   * 停止所有定时器
-   */
-  private stopAllTimers(): void {
-    // 停止账户更新定时器
-    for (const interval of this.updateIntervals.values()) {
-      clearInterval(interval)
-    }
-    this.updateIntervals.clear()
-
-    // 停止健康检查定时器
-    for (const interval of this.connectionHealthChecks.values()) {
-      clearInterval(interval)
-    }
-    this.connectionHealthChecks.clear()
-  }
-
-  /**
-   * 执行优雅关闭
-   */
-  private async performGracefulShutdown(): Promise<void> {
-    logger.info('🔄 执行优雅关闭')
-
-    // 可以在这里执行最后的状态保存等操作
-  }
-
-  /**
-   * 清理资源
-   */
-  private cleanup(): void {
-    this.accounts.clear()
-    this.accountConfigs.clear()
-    this.hedgingGroups.clear()
-    this.performanceMetrics.clear()
-    this.lastAccountUpdates.clear()
-    this.removeAllListeners()
-  }
-
-  /**
-   * 从对冲组移除账户(占位实现)
-   */
-  private async removeAccountFromHedgingGroup(groupId: string, accountId: string): Promise<void> {
-    const group = this.hedgingGroups.get(groupId)
-    if (group) {
-      group.accounts = group.accounts.filter(id => id !== accountId)
-      logger.info(`✅ 从对冲组 ${groupId} 移除账户 ${accountId}`)
-    }
-  }
-}
-
-export default UnifiedAccountManager

+ 0 - 391
src/core/accounts/models.ts

@@ -1,391 +0,0 @@
-/**
- * 🏦 ExchangeAccount - Delta中性控制平面账户模型
- *
- * 按照tasks规范重构的核心账户实体,支持:
- * - Delta中性控制参数
- * - 资金利用率目标管理 (50%-80%)
- * - 风险包络关联
- * - 代理会话管理
- * - 紧急控制状态
- */
-export interface ExchangeAccountConfig {
-  accountId: string // 主键,唯一标识
-  exchange: 'pacifica' | 'aster' | 'binance' // 交易所类型
-  accountName: string // 展示用别名
-  publicKey: string // 经过加密存储
-  privateKey?: string // 私钥(加密存储)
-  proxyProfile: string // 引用代理配置ID
-  utilizationTargetMin: number // 默认0.5 (50%)
-  utilizationTargetMax: number // 默认0.8 (80%)
-  deltaThreshold: number // BTC等值,默认0.0005
-  maxPositionValue: number // 账户允许的最大名义价值
-  stopLossConfigId: string // 引用止损模板
-  status: 'active' | 'paused' | 'emergency' // 账户状态
-  createdAt?: Date
-  updatedAt?: Date
-}
-
-export interface AccountMetrics {
-  currentUtilization: number // 当前资金利用率
-  currentDelta: number // 当前Delta敞口 (BTC等值)
-  netPosition: number // 净仓位
-  totalBalance: number // 总余额
-  availableBalance: number // 可用余额
-  unrealizedPnl: number // 未实现盈亏
-  leverage: number // 当前杠杆倍数
-  lastUpdate: Date // 最后更新时间
-}
-
-export interface DeltaControlParams {
-  targetDelta: number // 目标Delta (通常为0)
-  deltaThreshold: number // Delta阈值
-  rebalanceThreshold: number // 再平衡触发阈值
-  maxHedgeSize: number // 单次最大对冲大小
-  emergencyThreshold: number // 紧急对冲阈值
-  controlCycleInterval: number // 控制循环间隔(ms)
-}
-
-/**
- * ExchangeAccount - Delta中性控制平面的核心账户实体
- */
-export class ExchangeAccount {
-  private config: ExchangeAccountConfig
-  private metrics: AccountMetrics
-  private deltaParams: DeltaControlParams
-  private riskEnvelopeId?: string
-  private proxySessionIds: string[] = []
-  private lastDeltaCheck: Date = new Date()
-  private deltaHistory: Array<{ time: Date; delta: number; utilization: number }> = []
-
-  constructor(config: ExchangeAccountConfig) {
-    this.config = { ...config }
-    this.validateConfig()
-    this.initializeMetrics()
-    this.initializeDeltaParams()
-  }
-
-  /**
-   * 验证账户配置
-   */
-  private validateConfig(): void {
-    if (!this.config.accountId) {
-      throw new Error('ExchangeAccount: accountId is required')
-    }
-    if (this.config.utilizationTargetMin < 0 || this.config.utilizationTargetMin > 1) {
-      throw new Error('ExchangeAccount: utilizationTargetMin must be between 0 and 1')
-    }
-    if (this.config.utilizationTargetMax < 0 || this.config.utilizationTargetMax > 1) {
-      throw new Error('ExchangeAccount: utilizationTargetMax must be between 0 and 1')
-    }
-    if (this.config.utilizationTargetMin >= this.config.utilizationTargetMax) {
-      throw new Error('ExchangeAccount: utilizationTargetMin must be less than utilizationTargetMax')
-    }
-    if (this.config.deltaThreshold <= 0) {
-      throw new Error('ExchangeAccount: deltaThreshold must be positive')
-    }
-  }
-
-  /**
-   * 初始化账户指标
-   */
-  private initializeMetrics(): void {
-    this.metrics = {
-      currentUtilization: 0,
-      currentDelta: 0,
-      netPosition: 0,
-      totalBalance: 0,
-      availableBalance: 0,
-      unrealizedPnl: 0,
-      leverage: 1,
-      lastUpdate: new Date(),
-    }
-  }
-
-  /**
-   * 初始化Delta控制参数
-   */
-  private initializeDeltaParams(): void {
-    this.deltaParams = {
-      targetDelta: 0, // Delta中性目标
-      deltaThreshold: this.config.deltaThreshold,
-      rebalanceThreshold: this.config.deltaThreshold * 0.8, // 80%阈值时开始再平衡
-      maxHedgeSize: this.config.maxPositionValue * 0.1, // 最大10%仓位进行对冲
-      emergencyThreshold: this.config.deltaThreshold * 2, // 2倍阈值紧急对冲
-      controlCycleInterval: 8000, // 8秒控制循环
-    }
-  }
-
-  /**
-   * 更新账户指标
-   */
-  updateMetrics(newMetrics: Partial<AccountMetrics>): void {
-    this.metrics = {
-      ...this.metrics,
-      ...newMetrics,
-      lastUpdate: new Date(),
-    }
-
-    // 记录Delta历史
-    this.recordDeltaHistory()
-
-    // 检查是否需要Delta控制
-    this.checkDeltaNeutralRequirement()
-  }
-
-  /**
-   * 记录Delta历史
-   */
-  private recordDeltaHistory(): void {
-    this.deltaHistory.push({
-      time: new Date(),
-      delta: this.metrics.currentDelta,
-      utilization: this.metrics.currentUtilization,
-    })
-
-    // 保留最近100条记录
-    if (this.deltaHistory.length > 100) {
-      this.deltaHistory = this.deltaHistory.slice(-100)
-    }
-  }
-
-  /**
-   * 检查Delta中性要求
-   */
-  private checkDeltaNeutralRequirement(): boolean {
-    const deltaExceeded = Math.abs(this.metrics.currentDelta) > this.deltaParams.deltaThreshold
-    const utilizationOutOfRange =
-      this.metrics.currentUtilization < this.config.utilizationTargetMin ||
-      this.metrics.currentUtilization > this.config.utilizationTargetMax
-
-    if (deltaExceeded || utilizationOutOfRange) {
-      console.log(
-        `🚨 [${this.config.accountId}] Delta中性检查: Delta=${this.metrics.currentDelta.toFixed(6)}, 利用率=${(
-          this.metrics.currentUtilization * 100
-        ).toFixed(1)}%`,
-      )
-      return true
-    }
-
-    return false
-  }
-
-  /**
-   * 判断是否需要紧急对冲
-   */
-  needsEmergencyHedge(): boolean {
-    return (
-      Math.abs(this.metrics.currentDelta) > this.deltaParams.emergencyThreshold || this.config.status === 'emergency'
-    )
-  }
-
-  /**
-   * 判断是否需要再平衡
-   */
-  needsRebalance(): boolean {
-    return (
-      Math.abs(this.metrics.currentDelta) > this.deltaParams.rebalanceThreshold ||
-      this.metrics.currentUtilization < this.config.utilizationTargetMin ||
-      this.metrics.currentUtilization > this.config.utilizationTargetMax
-    )
-  }
-
-  /**
-   * 计算建议的对冲大小
-   */
-  calculateHedgeSize(): number {
-    const deltaDiff = this.metrics.currentDelta - this.deltaParams.targetDelta
-    let hedgeSize = Math.abs(deltaDiff)
-
-    // 限制最大对冲大小
-    hedgeSize = Math.min(hedgeSize, this.deltaParams.maxHedgeSize)
-
-    // 如果是紧急情况,使用更激进的对冲
-    if (this.needsEmergencyHedge()) {
-      hedgeSize = Math.min(Math.abs(deltaDiff), this.config.maxPositionValue * 0.2)
-    }
-
-    return hedgeSize
-  }
-
-  /**
-   * 计算目标利用率调整
-   */
-  calculateUtilizationAdjustment(): number {
-    const currentUtil = this.metrics.currentUtilization
-    const targetMin = this.config.utilizationTargetMin
-    const targetMax = this.config.utilizationTargetMax
-    const targetCenter = (targetMin + targetMax) / 2
-
-    if (currentUtil < targetMin) {
-      return targetCenter - currentUtil // 需要增加利用率
-    } else if (currentUtil > targetMax) {
-      return targetCenter - currentUtil // 需要减少利用率
-    }
-
-    return 0 // 在目标范围内
-  }
-
-  /**
-   * 设置紧急状态
-   */
-  setEmergencyStatus(reason: string): void {
-    this.config.status = 'emergency'
-    this.config.updatedAt = new Date()
-    console.log(`🚨 [${this.config.accountId}] 进入紧急状态: ${reason}`)
-  }
-
-  /**
-   * 重置为正常状态
-   */
-  resetToActive(): void {
-    this.config.status = 'active'
-    this.config.updatedAt = new Date()
-    console.log(`✅ [${this.config.accountId}] 恢复正常状态`)
-  }
-
-  /**
-   * 获取账户配置
-   */
-  getConfig(): ExchangeAccountConfig {
-    return { ...this.config }
-  }
-
-  /**
-   * 获取账户指标
-   */
-  getMetrics(): AccountMetrics {
-    return { ...this.metrics }
-  }
-
-  /**
-   * 获取Delta控制参数
-   */
-  getDeltaParams(): DeltaControlParams {
-    return { ...this.deltaParams }
-  }
-
-  /**
-   * 获取Delta历史
-   */
-  getDeltaHistory(): Array<{ time: Date; delta: number; utilization: number }> {
-    return [...this.deltaHistory]
-  }
-
-  /**
-   * 关联风险包络
-   */
-  setRiskEnvelope(envelopeId: string): void {
-    this.riskEnvelopeId = envelopeId
-  }
-
-  /**
-   * 添加代理会话
-   */
-  addProxySession(sessionId: string): void {
-    if (!this.proxySessionIds.includes(sessionId)) {
-      this.proxySessionIds.push(sessionId)
-    }
-  }
-
-  /**
-   * 移除代理会话
-   */
-  removeProxySession(sessionId: string): void {
-    this.proxySessionIds = this.proxySessionIds.filter(id => id !== sessionId)
-  }
-
-  /**
-   * 获取账户状态摘要
-   */
-  getStatusSummary(): any {
-    return {
-      accountId: this.config.accountId,
-      exchange: this.config.exchange,
-      status: this.config.status,
-      delta: {
-        current: this.metrics.currentDelta,
-        threshold: this.deltaParams.deltaThreshold,
-        needsHedge: this.needsEmergencyHedge(),
-        needsRebalance: this.needsRebalance(),
-      },
-      utilization: {
-        current: this.metrics.currentUtilization,
-        target: `${(this.config.utilizationTargetMin * 100).toFixed(0)}%-${(
-          this.config.utilizationTargetMax * 100
-        ).toFixed(0)}%`,
-        adjustment: this.calculateUtilizationAdjustment(),
-      },
-      position: {
-        net: this.metrics.netPosition,
-        total: this.metrics.totalBalance,
-        available: this.metrics.availableBalance,
-        pnl: this.metrics.unrealizedPnl,
-      },
-      riskEnvelopeId: this.riskEnvelopeId,
-      proxySessionCount: this.proxySessionIds.length,
-      lastUpdate: this.metrics.lastUpdate,
-    }
-  }
-}
-
-/**
- * 账户余额信息
- */
-export interface AccountBalance {
-  asset: string
-  total: string // 字符串表示,保留精度
-  available: string // 字符串表示,保留精度
-}
-
-/**
- * 账户仓位信息
- */
-export interface AccountPosition {
-  symbol: string
-  side: 'long' | 'short'
-  size: string // 字符串表示,保留精度
-  entryPrice: string // 字符串表示,保留精度
-  markPrice: string // 字符串表示,保留精度
-  unrealizedPnl: string // 字符串表示,保留精度
-}
-
-/**
- * 账户利用率信息
- */
-export interface AccountUtilization {
-  value: number // 数值型,便于对齐 50%-80% 目标
-  formula: string // 公式描述
-}
-
-/**
- * 账户同步请求
- */
-export interface AccountSyncRequest {
-  requestId: string
-  accounts: Array<{
-    accountId: string
-    exchange: string
-    nonce: number
-  }>
-}
-
-/**
- * 账户同步响应
- */
-export interface AccountSyncResponse {
-  requestId: string
-  timestamp: string
-  results: Array<{
-    accountId: string
-    status: 'success' | 'failed'
-    balances?: AccountBalance[]
-    positions?: AccountPosition[]
-    utilization?: AccountUtilization
-  }>
-  errors: Array<{
-    accountId: string
-    code: string
-    message: string
-    retryable?: boolean
-  }>
-}

+ 0 - 898
src/core/hedging/SamePlatformHedgingManager.ts

@@ -1,898 +0,0 @@
-import { Config } from '../../config/simpleEnv.js'
-import { httpClient } from '../../utils/httpClient.js'
-import { logger } from '../../utils/logger.js'
-import { PacificaProxyClient } from '../../exchanges/pacifica/PacificaProxyClient.js'
-import { OrderCreatePayload } from '../../exchanges/pacifica/OrdersAdapter.js'
-
-/**
- * 同一平台对冲管理器
- * 支持在同一交易所内使用不同账户进行对冲操作,通过代理实现网络隔离
- */
-export class SamePlatformHedgingManager {
-  private exchange: 'aster' | 'pacifica' | 'binance'
-  private accounts: Map<string, HedgeAccount>
-  private hedgePairs: Map<string, HedgePair>
-  private clients: Map<string, any> // 交易客户端实例
-  private riskLimits: RiskLimits // 风险限制配置
-
-  constructor(exchange: 'aster' | 'pacifica' | 'binance', riskLimits?: Partial<RiskLimits>) {
-    this.exchange = exchange
-    this.accounts = new Map()
-    this.hedgePairs = new Map()
-    this.clients = new Map()
-
-    // 初始化风险限制
-    this.riskLimits = {
-      maxPositionSize: riskLimits?.maxPositionSize || 1.0, // 单个仓位最大数量
-      maxTotalExposure: riskLimits?.maxTotalExposure || 5.0, // 总敞口最大值
-      maxAccountBalance: riskLimits?.maxAccountBalance || 10000, // 账户最大余额限制
-      minAccountBalance: riskLimits?.minAccountBalance || 100, // 账户最小余额要求
-      maxDailyTrades: riskLimits?.maxDailyTrades || 100, // 每日最大交易次数
-      maxSlippage: riskLimits?.maxSlippage || 0.02, // 最大滑点 2%
-      emergencyStopLoss: riskLimits?.emergencyStopLoss || 0.05, // 紧急止损 5%
-      enabled: riskLimits?.enabled ?? true,
-    }
-  }
-
-  /**
-   * 添加对冲账户
-   */
-  addAccount(accountId: string, config: HedgeAccountConfig): void {
-    const account: HedgeAccount = {
-      id: accountId,
-      exchange: this.exchange,
-      config,
-      positions: new Map(),
-      lastUpdate: 0,
-      proxyConfig: this.getProxyForAccount(accountId),
-    }
-
-    this.accounts.set(accountId, account)
-
-    // 创建对应的交易客户端
-    this.createTradingClient(accountId, config)
-
-    logger.info(`添加${this.exchange}对冲账户`, {
-      accountId,
-      hasProxy: !!account.proxyConfig,
-      exchange: this.exchange,
-    })
-  }
-
-  /**
-   * 创建对冲对
-   */
-  createHedgePair(
-    pairId: string,
-    longAccountId: string,
-    shortAccountId: string,
-    symbol: string,
-    targetRatio: number = 1.0,
-  ): void {
-    if (!this.accounts.has(longAccountId) || !this.accounts.has(shortAccountId)) {
-      throw new Error(`账户不存在: ${longAccountId} 或 ${shortAccountId}`)
-    }
-
-    const pair: HedgePair = {
-      id: pairId,
-      longAccountId,
-      shortAccountId,
-      symbol,
-      targetRatio,
-      currentLongPosition: 0,
-      currentShortPosition: 0,
-      netExposure: 0,
-      lastRebalance: 0,
-      isActive: true,
-    }
-
-    this.hedgePairs.set(pairId, pair)
-
-    logger.info(`创建${this.exchange}对冲对`, {
-      pairId,
-      longAccount: longAccountId,
-      shortAccount: shortAccountId,
-      symbol,
-      targetRatio,
-    })
-  }
-
-  /**
-   * 创建交易客户端
-   */
-  private createTradingClient(accountId: string, config: HedgeAccountConfig): void {
-    if (this.exchange === 'pacifica') {
-      const client = new PacificaProxyClient({
-        account: config.account,
-        privateKey: config.privateKey,
-        agentWallet: config.agentWallet,
-        agentPrivateKey: config.agentPrivateKey,
-      })
-      this.clients.set(accountId, client)
-    } else if (this.exchange === 'aster') {
-      // TODO: 实现Aster客户端
-      logger.warn('Aster交易客户端暂未实现', { accountId })
-    } else if (this.exchange === 'binance') {
-      // TODO: 实现Binance客户端
-      logger.warn('Binance交易客户端暂未实现', { accountId })
-    }
-  }
-
-  /**
-   * 获取交易客户端
-   */
-  private getTradingClient(accountId: string): any {
-    const client = this.clients.get(accountId)
-    if (!client) {
-      throw new Error(`未找到账户${accountId}的交易客户端`)
-    }
-    return client
-  }
-
-  /**
-   * 获取账户专用代理配置
-   */
-  private getProxyForAccount(accountId: string): string | undefined {
-    // 支持为不同账户配置不同的代理会话
-    // 这样可以模拟不同的网络来源,减少被识别为同一用户的风险
-
-    if (!Config.proxy.isConfigured(this.exchange)) {
-      return undefined
-    }
-
-    // 为每个账户生成唯一的会话标识
-    const accountSpecificProxy = Config.proxy.getUrl(this.exchange)
-    if (!accountSpecificProxy) return undefined
-
-    // 如果配置了会话管理,为每个账户创建不同的会话
-    if (this.exchange === 'aster' && Config.proxy.aster.sessionPrefix()) {
-      // 为不同账户生成不同的会话后缀
-      const accountSuffix = this.generateAccountSuffix(accountId)
-      // 这里可以扩展为每个账户使用不同的会话配置
-      return accountSpecificProxy // 暂时返回相同的URL,未来可以优化
-    }
-
-    return accountSpecificProxy
-  }
-
-  /**
-   * 为账户生成唯一后缀
-   */
-  private generateAccountSuffix(accountId: string): string {
-    // 基于账户ID生成稳定的后缀
-    let hash = 0
-    for (let i = 0; i < accountId.length; i++) {
-      const char = accountId.charCodeAt(i)
-      hash = (hash << 5) - hash + char
-      hash = hash & hash // 转换为32位整数
-    }
-    return Math.abs(hash).toString(36).substring(0, 6)
-  }
-
-  /**
-   * 更新账户仓位
-   */
-  async updateAccountPositions(accountId: string): Promise<void> {
-    const account = this.accounts.get(accountId)
-    if (!account) throw new Error(`账户不存在: ${accountId}`)
-
-    try {
-      // 使用账户专用代理请求仓位信息
-      const positions = await this.fetchPositions(account)
-
-      // 更新仓位缓存
-      account.positions.clear()
-      positions.forEach(pos => {
-        account.positions.set(pos.symbol, pos)
-      })
-
-      account.lastUpdate = Date.now()
-
-      logger.debug(`更新${this.exchange}账户仓位`, {
-        accountId,
-        positionCount: positions.length,
-        proxy: account.proxyConfig ? '启用' : '禁用',
-      })
-    } catch (error: any) {
-      logger.error(`更新账户仓位失败`, {
-        exchange: this.exchange,
-        accountId,
-        error: error.message,
-      })
-      throw error
-    }
-  }
-
-  /**
-   * 获取仓位信息(根据交易所实现)
-   */
-  private async fetchPositions(account: HedgeAccount): Promise<Position[]> {
-    const baseUrl = this.getExchangeApiUrl()
-    const endpoint = this.getPositionsEndpoint()
-
-    const response = await httpClient.get(`${baseUrl}${endpoint}`, {
-      exchange: this.exchange,
-      accountId: account.id,
-      timeout: 10000,
-      retries: 2,
-      headers: this.buildAuthHeaders(account),
-    })
-
-    if (!response.ok) {
-      throw new Error(`获取仓位失败: ${response.status}`)
-    }
-
-    return this.parsePositions(response.data)
-  }
-
-  /**
-   * 获取交易所API基础URL
-   */
-  private getExchangeApiUrl(): string {
-    switch (this.exchange) {
-      case 'aster':
-        return Config.aster.httpBase
-      case 'pacifica':
-        return Config.pacifica.baseUrl
-      case 'binance':
-        return Config.binance.baseUrl
-      default:
-        throw new Error(`不支持的交易所: ${this.exchange}`)
-    }
-  }
-
-  /**
-   * 获取仓位查询端点
-   */
-  private getPositionsEndpoint(): string {
-    switch (this.exchange) {
-      case 'aster':
-        return '/api/v1/positions'
-      case 'pacifica':
-        return '/api/v1/positions'
-      case 'binance':
-        return '/fapi/v2/positionRisk'
-      default:
-        throw new Error(`不支持的交易所: ${this.exchange}`)
-    }
-  }
-
-  /**
-   * 构建认证头(根据交易所实现)
-   */
-  private buildAuthHeaders(account: HedgeAccount): Record<string, string> {
-    // 这里需要根据具体交易所的认证方式实现
-    // 暂时返回空对象,实际使用时需要具体实现
-    return {}
-  }
-
-  /**
-   * 解析仓位数据(根据交易所格式实现)
-   */
-  private parsePositions(data: any): Position[] {
-    // 这里需要根据具体交易所的返回格式实现
-    // 暂时返回空数组,实际使用时需要具体实现
-    return []
-  }
-
-  /**
-   * 计算对冲对的净敞口
-   */
-  calculateNetExposure(pairId: string): number {
-    const pair = this.hedgePairs.get(pairId)
-    if (!pair) throw new Error(`对冲对不存在: ${pairId}`)
-
-    const longAccount = this.accounts.get(pair.longAccountId)
-    const shortAccount = this.accounts.get(pair.shortAccountId)
-
-    if (!longAccount || !shortAccount) {
-      throw new Error(`对冲对账户不完整: ${pairId}`)
-    }
-
-    const longPosition = longAccount.positions.get(pair.symbol)
-    const shortPosition = shortAccount.positions.get(pair.symbol)
-
-    const longSize = longPosition?.size || 0
-    const shortSize = shortPosition?.size || 0
-
-    pair.currentLongPosition = longSize
-    pair.currentShortPosition = shortSize
-    pair.netExposure = longSize + shortSize // 注意:空头为负数
-
-    return pair.netExposure
-  }
-
-  /**
-   * 执行对冲再平衡
-   */
-  async rebalanceHedgePair(pairId: string, tolerance: number = 0.01): Promise<boolean> {
-    const pair = this.hedgePairs.get(pairId)
-    if (!pair || !pair.isActive) return false
-
-    // 更新仓位信息
-    await Promise.all([
-      this.updateAccountPositions(pair.longAccountId),
-      this.updateAccountPositions(pair.shortAccountId),
-    ])
-
-    const netExposure = this.calculateNetExposure(pairId)
-
-    // 获取账户状态进行资金利用率分析
-    const longPosition = this.accountPositions.get(pair.longAccountId)?.get(pair.symbol) || 0
-    const shortPosition = this.accountPositions.get(pair.shortAccountId)?.get(pair.symbol) || 0
-
-    // 多维度平衡检查
-    const exposureDiff = Math.abs(netExposure)
-    const positionImbalance = Math.abs(Math.abs(longPosition) - Math.abs(shortPosition))
-
-    console.log(`🔍 [平衡检查] 净敞口: ${netExposure.toFixed(4)}, 仓位不平衡: ${positionImbalance.toFixed(4)}`)
-
-    // 更严格的平衡标准
-    const needsRebalance = exposureDiff > tolerance || positionImbalance > 0.002
-
-    if (!needsRebalance) {
-      logger.debug(`对冲对无需再平衡`, {
-        pairId,
-        netExposure,
-        positionImbalance,
-        tolerance,
-        exchange: this.exchange,
-      })
-      return false
-    }
-
-    console.log(
-      `🚨 [需要平衡] 净敞口: ${exposureDiff.toFixed(4)} > ${tolerance} 或仓位不平衡: ${positionImbalance.toFixed(
-        4,
-      )} > 0.002`,
-    )
-
-    // 执行再平衡交易
-    try {
-      const success = await this.executeRebalanceTrades(pair, netExposure)
-
-      if (success) {
-        pair.lastRebalance = Date.now()
-        logger.info(`对冲再平衡成功`, {
-          pairId,
-          netExposure,
-          exchange: this.exchange,
-        })
-      }
-
-      return success
-    } catch (error: any) {
-      logger.error(`对冲再平衡失败`, {
-        pairId,
-        error: error.message,
-        exchange: this.exchange,
-      })
-      return false
-    }
-  }
-
-  /**
-   * 执行再平衡交易 - 改进版:真正的双向平衡
-   */
-  private async executeRebalanceTrades(pair: HedgePair, netExposure: number): Promise<boolean> {
-    console.log(`🔄 [再平衡] 开始双向平衡,当前净敞口: ${netExposure.toFixed(4)} BTC`)
-
-    // 获取两个账户的当前状态
-    const longPosition = this.accountPositions.get(pair.longAccountId)?.get(pair.symbol) || 0
-    const shortPosition = this.accountPositions.get(pair.shortAccountId)?.get(pair.symbol) || 0
-
-    console.log(`📊 [再平衡] 当前仓位 - 多头账户: ${longPosition.toFixed(4)}, 空头账户: ${shortPosition.toFixed(4)}`)
-
-    // 计算理想的平衡状态:两个账户仓位大小相等,方向相反
-    const totalAbsPosition = Math.abs(longPosition) + Math.abs(shortPosition)
-    const idealPositionSize = totalAbsPosition / 2
-
-    if (idealPositionSize < 0.0005) {
-      console.log(`ℹ️ [再平衡] 仓位太小,无需平衡`)
-      return false
-    }
-
-    // 计算每个账户需要的调整量
-    const longAdjustment = idealPositionSize - Math.abs(longPosition)
-    const shortAdjustment = idealPositionSize - Math.abs(shortPosition)
-
-    console.log(`🎯 [再平衡] 理想仓位: ${idealPositionSize.toFixed(4)} BTC`)
-    console.log(`📈 [再平衡] 调整量 - 多头: ${longAdjustment.toFixed(4)}, 空头: ${shortAdjustment.toFixed(4)}`)
-
-    const minOrderSize = 0.0003 // 降低最小订单量
-    const orders = []
-
-    // 生成双向调整订单
-    if (Math.abs(longAdjustment) >= minOrderSize) {
-      if (longAdjustment > 0) {
-        // 多头账户需要增加多头仓位
-        orders.push({
-          accountId: pair.longAccountId,
-          side: 'bid' as const,
-          amount: Math.abs(longAdjustment),
-          reason: '再平衡-增加多头仓位',
-        })
-      } else {
-        // 多头账户需要减少仓位
-        orders.push({
-          accountId: pair.longAccountId,
-          side: 'ask' as const,
-          amount: Math.abs(longAdjustment),
-          reason: '再平衡-减少多头仓位',
-        })
-      }
-    }
-
-    if (Math.abs(shortAdjustment) >= minOrderSize) {
-      if (shortAdjustment > 0) {
-        // 空头账户需要增加空头仓位
-        orders.push({
-          accountId: pair.shortAccountId,
-          side: 'ask' as const,
-          amount: Math.abs(shortAdjustment),
-          reason: '再平衡-增加空头仓位',
-        })
-      } else {
-        // 空头账户需要减少仓位
-        orders.push({
-          accountId: pair.shortAccountId,
-          side: 'bid' as const,
-          amount: Math.abs(shortAdjustment),
-          reason: '再平衡-减少空头仓位',
-        })
-      }
-    }
-
-    if (orders.length === 0) {
-      console.log(`ℹ️ [再平衡] 调整量都太小,跳过再平衡`)
-      return false
-    }
-
-    // 执行双向调整订单
-    try {
-      console.log(`🔄 [再平衡] 执行${orders.length}个调整订单`)
-
-      for (const order of orders) {
-        console.log(`📝 [再平衡] ${order.accountId}: ${order.side} ${order.amount.toFixed(4)} BTC - ${order.reason}`)
-
-        await this.executeHedgeOrder(order.accountId, pair.symbol, order.amount, order.side)
-
-        // 短暂延迟避免过快执行
-        await new Promise(resolve => setTimeout(resolve, 200))
-      }
-
-      console.log(`✅ [再平衡] 双向平衡完成`)
-      return true
-    } catch (error: any) {
-      logger.error(`执行双向再平衡交易失败`, {
-        pair: pair.id,
-        netExposure,
-        orders,
-        error: error.message,
-        exchange: this.exchange,
-      })
-      return false
-    }
-  }
-
-  /**
-   * 风险检查
-   */
-  private async checkRiskLimits(
-    accountId: string,
-    symbol: string,
-    amount: number,
-    side: 'bid' | 'ask',
-  ): Promise<{ allowed: boolean; reason?: string }> {
-    if (!this.riskLimits.enabled) {
-      return { allowed: true }
-    }
-
-    try {
-      // 检查订单量限制
-      if (amount > this.riskLimits.maxPositionSize) {
-        return {
-          allowed: false,
-          reason: `订单量${amount}超过单个仓位最大限制${this.riskLimits.maxPositionSize}`,
-        }
-      }
-
-      // 检查账户余额
-      const client = this.getTradingClient(accountId)
-      const balances = await client.getBalances()
-
-      if (balances && Array.isArray(balances)) {
-        const usdBalance = balances.find(b => b.asset === 'USDT' || b.asset === 'USD' || b.asset === 'USDC')
-
-        if (usdBalance) {
-          const balance = parseFloat(usdBalance.free || usdBalance.available || '0')
-
-          if (balance < this.riskLimits.minAccountBalance) {
-            return {
-              allowed: false,
-              reason: `账户余额${balance}低于最小要求${this.riskLimits.minAccountBalance}`,
-            }
-          }
-        }
-      }
-
-      // 检查总敞口
-      const totalExposure = await this.calculateTotalExposure(accountId)
-      const newExposure = side === 'bid' ? totalExposure + amount : totalExposure - amount
-
-      if (Math.abs(newExposure) > this.riskLimits.maxTotalExposure) {
-        return {
-          allowed: false,
-          reason: `新的总敞口${Math.abs(newExposure)}将超过最大限制${this.riskLimits.maxTotalExposure}`,
-        }
-      }
-
-      logger.info('风险检查通过', {
-        accountId,
-        symbol,
-        amount,
-        side,
-        currentExposure: totalExposure,
-        newExposure,
-      })
-
-      return { allowed: true }
-    } catch (error: any) {
-      logger.error('风险检查失败', {
-        accountId,
-        symbol,
-        error: error.message,
-      })
-
-      return {
-        allowed: false,
-        reason: `风险检查失败: ${error.message}`,
-      }
-    }
-  }
-
-  /**
-   * 计算账户总敞口
-   */
-  private async calculateTotalExposure(accountId: string): Promise<number> {
-    try {
-      const client = this.getTradingClient(accountId)
-      const positions = await client.getPositions()
-
-      let totalExposure = 0
-
-      if (positions && Array.isArray(positions)) {
-        for (const position of positions) {
-          const size = parseFloat(position.size || position.amount || '0')
-          totalExposure += Math.abs(size)
-        }
-      }
-
-      return totalExposure
-    } catch (error: any) {
-      logger.error('计算总敞口失败', {
-        accountId,
-        error: error.message,
-      })
-      return 0
-    }
-  }
-
-  /**
-   * 紧急止损检查
-   */
-  private async checkEmergencyStopLoss(accountId: string): Promise<boolean> {
-    try {
-      const client = this.getTradingClient(accountId)
-      const positions = await client.getPositions()
-
-      if (!positions || !Array.isArray(positions)) {
-        return false
-      }
-
-      for (const position of positions) {
-        const pnlPercent = parseFloat(position.pnlPercent || position.unrealizedPnlPercent || '0')
-
-        if (Math.abs(pnlPercent) > this.riskLimits.emergencyStopLoss) {
-          logger.warn('触发紧急止损', {
-            accountId,
-            symbol: position.symbol,
-            pnlPercent,
-            emergencyStopLoss: this.riskLimits.emergencyStopLoss,
-          })
-
-          // 执行紧急平仓
-          await this.emergencyClosePosition(accountId, position)
-          return true
-        }
-      }
-
-      return false
-    } catch (error: any) {
-      logger.error('紧急止损检查失败', {
-        accountId,
-        error: error.message,
-      })
-      return false
-    }
-  }
-
-  /**
-   * 紧急平仓
-   */
-  private async emergencyClosePosition(accountId: string, position: any): Promise<void> {
-    try {
-      const client = this.getTradingClient(accountId)
-      const account = this.accounts.get(accountId)
-
-      if (!account) {
-        throw new Error(`账户${accountId}不存在`)
-      }
-
-      const size = Math.abs(parseFloat(position.size || position.amount || '0'))
-      const isLong = parseFloat(position.size || position.amount || '0') > 0
-      const side = isLong ? 'ask' : 'bid' // 平多头用卖单,平空头用买单
-
-      const payload: OrderCreatePayload = {
-        account: account.config.account || '',
-        symbol: position.symbol,
-        amount: size.toString(),
-        side,
-        reduceOnly: true, // 只减仓
-        slippagePercent: '1.0', // 紧急情况允许更大滑点
-      }
-
-      logger.warn('执行紧急平仓', {
-        accountId,
-        symbol: position.symbol,
-        size,
-        side,
-        isLong,
-      })
-
-      await client.createMarketOrder(payload)
-
-      logger.info('紧急平仓执行成功', {
-        accountId,
-        symbol: position.symbol,
-        size,
-        side,
-      })
-    } catch (error: any) {
-      logger.error('紧急平仓失败', {
-        accountId,
-        position: position.symbol,
-        error: error.message,
-      })
-    }
-  }
-
-  /**
-   * 执行对冲订单
-   */
-  private async executeHedgeOrder(
-    accountId: string,
-    symbol: string,
-    amount: number,
-    side: 'bid' | 'ask',
-  ): Promise<any> {
-    const client = this.getTradingClient(accountId)
-    const account = this.accounts.get(accountId)
-
-    if (!account) {
-      throw new Error(`账户${accountId}不存在`)
-    }
-
-    // 执行风险检查
-    const riskCheck = await this.checkRiskLimits(accountId, symbol, amount, side)
-    if (!riskCheck.allowed) {
-      throw new Error(`风险控制拒绝: ${riskCheck.reason}`)
-    }
-
-    // 执行紧急止损检查
-    const emergencyTriggered = await this.checkEmergencyStopLoss(accountId)
-    if (emergencyTriggered) {
-      throw new Error(`触发紧急止损,暂停交易`)
-    }
-
-    if (this.exchange === 'pacifica') {
-      const payload: OrderCreatePayload = {
-        account: account.config.account || '',
-        symbol,
-        amount: amount.toString(),
-        side,
-        reduceOnly: false,
-        slippagePercent: '0.5', // 0.5%滑点
-      }
-
-      logger.info(`执行Pacifica对冲订单`, {
-        accountId,
-        symbol,
-        amount,
-        side,
-        proxy: !!account.proxyConfig,
-      })
-
-      // 使用市价单确保成交
-      const result = await client.createMarketOrder(payload)
-
-      logger.info(`Pacifica对冲订单执行成功`, {
-        accountId,
-        symbol,
-        side,
-        orderId: result.orderId || result.order_id,
-        success: result.success,
-      })
-
-      return result
-    } else {
-      throw new Error(`交易所${this.exchange}的下单功能暂未实现`)
-    }
-  }
-
-  /**
-   * 批量执行对冲交易
-   */
-  async executeBatchHedge(
-    orders: Array<{
-      accountId: string
-      symbol: string
-      amount: number
-      side: 'bid' | 'ask'
-      orderType?: 'market' | 'limit'
-      price?: number
-    }>,
-  ): Promise<Array<{ success: boolean; orderId?: string; error?: string }>> {
-    const results: Array<{ success: boolean; orderId?: string; error?: string }> = []
-
-    logger.info(`开始批量对冲执行`, {
-      orderCount: orders.length,
-      exchange: this.exchange,
-    })
-
-    for (const order of orders) {
-      try {
-        const result = await this.executeHedgeOrder(order.accountId, order.symbol, order.amount, order.side)
-
-        results.push({
-          success: true,
-          orderId: result.orderId || result.order_id,
-        })
-      } catch (error: any) {
-        logger.error(`批量对冲订单执行失败`, {
-          accountId: order.accountId,
-          symbol: order.symbol,
-          error: error.message,
-        })
-
-        results.push({
-          success: false,
-          error: error.message,
-        })
-      }
-    }
-
-    logger.info(`批量对冲执行完成`, {
-      total: orders.length,
-      successful: results.filter(r => r.success).length,
-      failed: results.filter(r => !r.success).length,
-      exchange: this.exchange,
-    })
-
-    return results
-  }
-
-  /**
-   * 获取所有对冲对状态
-   */
-  getHedgePairStatuses(): HedgePairStatus[] {
-    const statuses: HedgePairStatus[] = []
-
-    for (const [pairId, pair] of this.hedgePairs) {
-      const netExposure = this.calculateNetExposure(pairId)
-
-      statuses.push({
-        pairId,
-        symbol: pair.symbol,
-        longAccount: pair.longAccountId,
-        shortAccount: pair.shortAccountId,
-        longPosition: pair.currentLongPosition,
-        shortPosition: pair.currentShortPosition,
-        netExposure,
-        targetRatio: pair.targetRatio,
-        isActive: pair.isActive,
-        lastRebalance: pair.lastRebalance,
-        exchange: this.exchange,
-      })
-    }
-
-    return statuses
-  }
-
-  /**
-   * 停用对冲对
-   */
-  deactivateHedgePair(pairId: string): void {
-    const pair = this.hedgePairs.get(pairId)
-    if (pair) {
-      pair.isActive = false
-      logger.info(`停用对冲对`, { pairId, exchange: this.exchange })
-    }
-  }
-
-  /**
-   * 激活对冲对
-   */
-  activateHedgePair(pairId: string): void {
-    const pair = this.hedgePairs.get(pairId)
-    if (pair) {
-      pair.isActive = true
-      logger.info(`激活对冲对`, { pairId, exchange: this.exchange })
-    }
-  }
-}
-
-// 类型定义
-interface HedgeAccount {
-  id: string
-  exchange: 'aster' | 'pacifica' | 'binance'
-  config: HedgeAccountConfig
-  positions: Map<string, Position>
-  lastUpdate: number
-  proxyConfig?: string
-}
-
-interface HedgeAccountConfig {
-  apiKey?: string
-  apiSecret?: string
-  privateKey?: string
-  // 其他认证信息
-  [key: string]: any
-}
-
-interface HedgePair {
-  id: string
-  longAccountId: string
-  shortAccountId: string
-  symbol: string
-  targetRatio: number
-  currentLongPosition: number
-  currentShortPosition: number
-  netExposure: number
-  lastRebalance: number
-  isActive: boolean
-}
-
-interface Position {
-  symbol: string
-  size: number
-  side: 'long' | 'short'
-  entryPrice: number
-  markPrice: number
-  unrealizedPnl: number
-}
-
-interface HedgePairStatus {
-  pairId: string
-  symbol: string
-  longAccount: string
-  shortAccount: string
-  longPosition: number
-  shortPosition: number
-  netExposure: number
-  targetRatio: number
-  isActive: boolean
-  lastRebalance: number
-  exchange: string
-}
-
-interface RiskLimits {
-  maxPositionSize: number // 单个仓位最大数量
-  maxTotalExposure: number // 总敞口最大值
-  maxAccountBalance: number // 账户最大余额限制
-  minAccountBalance: number // 账户最小余额要求
-  maxDailyTrades: number // 每日最大交易次数
-  maxSlippage: number // 最大滑点
-  emergencyStopLoss: number // 紧急止损阈值
-  enabled: boolean // 是否启用风险控制
-}

+ 0 - 362
src/core/hedging/UnifiedHedgingExecutor.ts

@@ -1,362 +0,0 @@
-/**
- * 统一对冲执行器
- * 完全基于 ExchangeAdapter 接口,实现原子配对交易和智能回退逻辑
- */
-
-import { ExchangeAdapter, PlaceOrderReq, Order } from '../../exchanges/ExchangeAdapter'
-import { PrecisionValidator } from '../../utils/precision'
-import { AdapterErrorHandler } from '../../exchanges/AdapterErrorHandler'
-import type { AdapterError } from '../../exchanges/AdapterErrorHandler'
-import { HedgeRequest, ExecutionResult } from './types'
-import { hedgeCalculator } from './hedgeCalculator'
-import { EventEmitter } from 'events'
-
-export interface AdapterPair {
-  primary: ExchangeAdapter // 主交易所(执行对冲)
-  secondary?: ExchangeAdapter // 备用交易所
-  primaryId: string // 主交易所标识
-  secondaryId?: string // 备用交易所标识
-}
-
-export interface ExecutionConfig {
-  maxRetries: number // 最大重试次数
-  timeoutMs: number // 执行超时时间
-  atomicTimeout: number // 原子操作超时时间
-  enableRollback: boolean // 启用回滚机制
-  slippageTolerance: number // 滑点容忍度
-  positionSizeLimit: number // 单次操作仓位大小限制
-}
-
-export interface HedgeExecution {
-  id: string
-  timestamp: number
-  request: HedgeRequest
-  primaryOrder?: Order
-  secondaryOrder?: Order
-  status: 'pending' | 'partial' | 'completed' | 'failed' | 'rolled_back'
-  error?: AdapterError
-  netExposure: number // 净敞口
-  executionLatency: number // 执行延迟(ms)
-}
-
-export class UnifiedHedgingExecutor extends EventEmitter {
-  private executions = new Map<string, HedgeExecution>()
-  private netExposureBySymbol = new Map<string, number>()
-
-  constructor(private config: ExecutionConfig) {
-    super()
-    this.startNetExposureMonitor()
-  }
-
-  /**
-   * 执行对冲交易
-   */
-  async execute(request: HedgeRequest, adapters: AdapterPair): Promise<ExecutionResult> {
-    const executionId = this.generateExecutionId()
-    const startTime = Date.now()
-
-    const execution: HedgeExecution = {
-      id: executionId,
-      timestamp: startTime,
-      request,
-      status: 'pending',
-      netExposure: 0,
-      executionLatency: 0,
-    }
-
-    this.executions.set(executionId, execution)
-    this.emit('execution_started', execution)
-
-    try {
-      // 1. 计算对冲决策
-      const decision = hedgeCalculator.decide(request)
-      if (!decision.shouldHedge) {
-        execution.status = 'completed'
-        execution.executionLatency = Date.now() - startTime
-        this.emit('execution_completed', execution)
-        return { success: true, executedQuantity: 0, executedPrice: 0 }
-      }
-
-      // 2. 验证适配器状态
-      await this.validateAdapters(adapters)
-
-      // 3. 准备订单参数
-      const orderParams = await this.prepareOrders(request, decision, adapters)
-
-      // 4. 执行原子配对交易
-      const result = await this.executeAtomicPair(orderParams, adapters, execution)
-
-      execution.executionLatency = Date.now() - startTime
-      this.emit('execution_completed', execution)
-
-      return result
-    } catch (error) {
-      execution.error =
-        error instanceof AdapterError ? error : AdapterErrorHandler.handleError('unified_executor', error, 'execute')
-      execution.status = 'failed'
-      execution.executionLatency = Date.now() - startTime
-
-      this.emit('execution_failed', execution)
-
-      // 尝试回滚
-      if (this.config.enableRollback) {
-        await this.attemptRollback(execution, adapters)
-      }
-
-      throw execution.error
-    } finally {
-      // 更新净敞口
-      this.updateNetExposure(request.symbol, execution)
-    }
-  }
-
-  /**
-   * 准备订单参数
-   */
-  private async prepareOrders(request: HedgeRequest, decision: any, adapters: AdapterPair) {
-    const side = decision.hedgeQuantity > 0 ? 'BUY' : 'SELL'
-    const absQuantity = Math.abs(decision.hedgeQuantity)
-
-    // 获取市场深度用于价格发现
-    const primaryDepth = await adapters.primary.depth(request.symbol, 20)
-    const bestPrice = side === 'BUY' ? primaryDepth.asks[0]?.price : primaryDepth.bids[0]?.price
-
-    if (!bestPrice) {
-      throw new Error(`无法获取 ${request.symbol} 的有效价格`)
-    }
-
-    // 精度验证和调整
-    const adjustedParams = PrecisionValidator.adjustOrderParams(
-      adapters.primaryId,
-      request.symbol,
-      bestPrice,
-      absQuantity,
-    )
-
-    if (!adjustedParams.valid) {
-      throw new Error(`订单参数校验失败: ${adjustedParams.warnings.join(', ')}`)
-    }
-
-    // 检查仓位大小限制
-    const orderNotional = Number(adjustedParams.price) * Number(adjustedParams.quantity)
-    if (orderNotional > this.config.positionSizeLimit) {
-      throw new Error(`订单金额 ${orderNotional} 超过限制 ${this.config.positionSizeLimit}`)
-    }
-
-    return {
-      symbol: request.symbol,
-      side: side as 'BUY' | 'SELL',
-      type: decision.method === 'spot' ? ('MARKET' as const) : ('LIMIT' as const),
-      quantity: adjustedParams.quantity,
-      price: adjustedParams.price,
-      clientOrderId: `hedge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
-    }
-  }
-
-  /**
-   * 执行原子配对交易
-   */
-  private async executeAtomicPair(
-    orderParams: PlaceOrderReq,
-    adapters: AdapterPair,
-    execution: HedgeExecution,
-  ): Promise<ExecutionResult> {
-    const promises: Promise<Order>[] = []
-
-    // 主交易所下单
-    promises.push(adapters.primary.placeOrder(orderParams))
-
-    // 如果有备用交易所,同时下单
-    if (adapters.secondary) {
-      promises.push(adapters.secondary.placeOrder(orderParams))
-    }
-
-    try {
-      // 等待所有订单完成或超时
-      const orders = await Promise.race([
-        Promise.all(promises),
-        new Promise<never>((_, reject) =>
-          setTimeout(() => reject(new Error('原子操作超时')), this.config.atomicTimeout),
-        ),
-      ])
-
-      execution.primaryOrder = orders[0]
-      if (orders[1]) execution.secondaryOrder = orders[1]
-
-      // 验证执行结果
-      const success = orders.every(
-        order => order.status === 'NEW' || order.status === 'FILLED' || order.status === 'PARTIALLY_FILLED',
-      )
-
-      if (!success) {
-        throw new Error('部分订单失败')
-      }
-
-      execution.status = 'completed'
-
-      return {
-        success: true,
-        orderId: execution.primaryOrder.id,
-        executedQuantity: Number(execution.primaryOrder.origQty),
-        executedPrice: Number(execution.primaryOrder.price || 0),
-      }
-    } catch (error) {
-      // 如果部分订单成功,标记为部分成功并尝试回滚
-      execution.status = 'partial'
-      throw error
-    }
-  }
-
-  /**
-   * 尝试回滚已执行的订单
-   */
-  private async attemptRollback(execution: HedgeExecution, adapters: AdapterPair): Promise<void> {
-    const rollbackPromises: Promise<void>[] = []
-
-    try {
-      if (execution.primaryOrder) {
-        rollbackPromises.push(adapters.primary.cancelOrder(execution.request.symbol, execution.primaryOrder.id))
-      }
-
-      if (execution.secondaryOrder && adapters.secondary) {
-        rollbackPromises.push(adapters.secondary.cancelOrder(execution.request.symbol, execution.secondaryOrder.id))
-      }
-
-      await Promise.allSettled(rollbackPromises)
-      execution.status = 'rolled_back'
-
-      this.emit('execution_rolled_back', execution)
-      console.info(`🔄 对冲执行 ${execution.id} 已回滚`)
-    } catch (rollbackError) {
-      console.error(`❌ 回滚失败 ${execution.id}:`, rollbackError)
-      this.emit('rollback_failed', { execution, error: rollbackError })
-    }
-  }
-
-  /**
-   * 验证适配器状态
-   */
-  private async validateAdapters(adapters: AdapterPair): Promise<void> {
-    const validationPromises = [this.validateAdapter(adapters.primary, adapters.primaryId)]
-
-    if (adapters.secondary) {
-      validationPromises.push(this.validateAdapter(adapters.secondary, adapters.secondaryId!))
-    }
-
-    await Promise.all(validationPromises)
-  }
-
-  /**
-   * 验证单个适配器
-   */
-  private async validateAdapter(adapter: ExchangeAdapter, adapterId: string): Promise<void> {
-    try {
-      const time = await adapter.time()
-      if (!time || Math.abs(Date.now() - time) > 10000) {
-        throw new Error(`${adapterId} 时间同步失败`)
-      }
-    } catch (error) {
-      throw new Error(`${adapterId} 适配器验证失败: ${error.message}`)
-    }
-  }
-
-  /**
-   * 更新净敞口
-   */
-  private updateNetExposure(symbol: string, execution: HedgeExecution): void {
-    const current = this.netExposureBySymbol.get(symbol) || 0
-
-    if (execution.status === 'completed' && execution.primaryOrder) {
-      const orderQty = Number(execution.primaryOrder.origQty)
-      const delta = execution.primaryOrder.side === 'BUY' ? orderQty : -orderQty
-
-      execution.netExposure = delta
-      this.netExposureBySymbol.set(symbol, current + delta)
-
-      this.emit('net_exposure_updated', { symbol, previous: current, current: current + delta })
-    }
-  }
-
-  /**
-   * 启动净敞口监控
-   */
-  private startNetExposureMonitor(): void {
-    setInterval(() => {
-      for (const [symbol, exposure] of this.netExposureBySymbol.entries()) {
-        if (Math.abs(exposure) > 0.01) {
-          // 净敞口阈值
-          this.emit('net_exposure_warning', { symbol, exposure })
-        }
-      }
-    }, 30000) // 每30秒检查一次
-  }
-
-  /**
-   * 强制净零操作
-   */
-  async forceNetZero(symbol: string, adapters: AdapterPair): Promise<void> {
-    const netExposure = this.netExposureBySymbol.get(symbol) || 0
-
-    if (Math.abs(netExposure) < 0.001) return // 已经足够接近零
-
-    console.info(`🎯 强制净零操作: ${symbol}, 当前敞口: ${netExposure}`)
-
-    // 创建相反方向的订单来中和敞口
-    const side = netExposure > 0 ? 'SELL' : 'BUY'
-    const quantity = Math.abs(netExposure)
-
-    const orderParams: PlaceOrderReq = {
-      symbol,
-      side,
-      type: 'MARKET',
-      quantity: String(quantity),
-      clientOrderId: `zero_${Date.now()}`,
-    }
-
-    try {
-      await adapters.primary.placeOrder(orderParams)
-      this.netExposureBySymbol.set(symbol, 0)
-      this.emit('net_zero_completed', { symbol, previousExposure: netExposure })
-    } catch (error) {
-      this.emit('net_zero_failed', { symbol, exposure: netExposure, error })
-      throw error
-    }
-  }
-
-  /**
-   * 获取执行统计
-   */
-  getExecutionStats(): {
-    totalExecutions: number
-    successRate: number
-    averageLatency: number
-    netExposures: Map<string, number>
-  } {
-    const executions = Array.from(this.executions.values())
-    const completed = executions.filter(e => e.status === 'completed')
-
-    return {
-      totalExecutions: executions.length,
-      successRate: completed.length / executions.length,
-      averageLatency: completed.reduce((sum, e) => sum + e.executionLatency, 0) / completed.length,
-      netExposures: new Map(this.netExposureBySymbol),
-    }
-  }
-
-  /**
-   * 清理过期执行记录
-   */
-  cleanup(maxAgeMs = 24 * 60 * 60 * 1000): void {
-    const cutoff = Date.now() - maxAgeMs
-
-    for (const [id, execution] of this.executions.entries()) {
-      if (execution.timestamp < cutoff) {
-        this.executions.delete(id)
-      }
-    }
-  }
-
-  private generateExecutionId(): string {
-    return `hedge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
-  }
-}

+ 0 - 49
src/core/hedging/hedgeCalculator.ts

@@ -1,49 +0,0 @@
-import { HedgeDecision, HedgeRequest } from './types'
-
-export class HedgeCalculator {
-  decide(req: HedgeRequest): HedgeDecision {
-    const { perpPosition, prices, funding, config } = req
-
-    // 非开仓状态不对冲
-    if (!perpPosition.isOpen || perpPosition.size === 0) {
-      return { shouldHedge: false, method: config.preferredMethod, hedgeQuantity: 0, reason: 'position_closed' }
-    }
-
-    const positionNotionalUsd = Math.abs(perpPosition.size * prices.perpPrice)
-    if (positionNotionalUsd < config.thresholds.minNotionalUSD) {
-      return { shouldHedge: false, method: config.preferredMethod, hedgeQuantity: 0, reason: 'notional_below_min' }
-    }
-
-    // 计算当前 delta 偏差(简化:方向 * 数量)
-    const direction = perpPosition.side === 'long' ? 1 : -1
-    const currentDelta = direction * perpPosition.size // 以 base 数量计
-
-    // 目标 delta = 0,考虑相关系数与价格换算
-    const hedgeQtyRaw =
-      -currentDelta * (prices.perpPrice / prices.hedgePrice) * Math.max(0, Math.min(1, prices.correlation || 1))
-
-    // 偏差阈值控制:若需要调整的数量占仓位比例过小则不执行
-    const deltaDeviationPct = Math.abs(hedgeQtyRaw) / Math.max(1e-9, Math.abs(perpPosition.size))
-    if (deltaDeviationPct < config.thresholds.deltaDeviationPct) {
-      return { shouldHedge: false, method: config.preferredMethod, hedgeQuantity: 0, reason: 'delta_within_threshold' }
-    }
-
-    // 资金费率驱动:若费率绝对值低于门槛则不进行“费率对冲”
-    if (Math.abs(funding.fundingRate) < config.thresholds.minFundingRate) {
-      return { shouldHedge: false, method: config.preferredMethod, hedgeQuantity: 0, reason: 'funding_rate_low' }
-    }
-
-    // 粗略估算单周期资金费收益(正费率多付,负费率可赚)
-    const expectedFundingPnlPerPeriod = -funding.fundingRate * positionNotionalUsd
-
-    return {
-      shouldHedge: true,
-      method: config.preferredMethod,
-      hedgeQuantity: hedgeQtyRaw,
-      reason: 'delta_neutral_funding_driven',
-      expectedFundingPnlPerPeriod,
-    }
-  }
-}
-
-export const hedgeCalculator = new HedgeCalculator()

+ 0 - 65
src/core/hedging/router.ts

@@ -1,65 +0,0 @@
-import { RouterQuote, ExecutionPlan } from './types'
-import { walletManager } from '../../infrastructure/wallet/walletManager'
-import { AsterAdapter, AsterConfig } from '../../exchanges/aster/asterAdapter'
-
-export class TradeRouter {
-  private aster?: AsterAdapter
-
-  constructor() {
-    const asterRpc = process.env.ASTER_RPC_URL
-    const asterChainId = process.env.ASTER_CHAIN_ID ? Number(process.env.ASTER_CHAIN_ID) : undefined
-    const asterRouter = process.env.ASTER_ROUTER_ADDRESS
-    if (asterRpc && asterChainId && asterRouter) {
-      const cfg: AsterConfig = { rpcUrl: asterRpc, chainId: asterChainId, routerAddress: asterRouter }
-      this.aster = new AsterAdapter(cfg, walletManager.wallet || undefined)
-    }
-  }
-
-  async quoteSpot(symbol: string, quantity: number): Promise<RouterQuote> {
-    const price = 0
-    return {
-      method: 'spot',
-      expectedIn: Math.abs(quantity),
-      expectedOut: Math.abs(quantity) * price,
-      price,
-      slippage: 0.0,
-      gasEstimateUSD: 0,
-      route: 'spot:placeholder',
-    }
-  }
-
-  async quotePerp(symbol: string, quantity: number): Promise<RouterQuote> {
-    if (!this.aster) throw new Error('Aster 适配器未配置')
-    const side = quantity > 0 ? 'long' : 'short'
-    const q = await this.aster.quote({ symbol, side, quantity: Math.abs(quantity), slippage: 0.005 })
-    return {
-      method: 'perp',
-      expectedIn: Math.abs(quantity),
-      expectedOut: Math.abs(quantity) * q.expectedPrice,
-      price: q.expectedPrice,
-      slippage: 0.0,
-      gasEstimateUSD: 0,
-      route: 'aster:router',
-    }
-  }
-
-  async execute(plan: ExecutionPlan) {
-    if (plan.method === 'spot') {
-      const addr = await walletManager.getAddress()
-      return { success: true, txHash: `0xspot_${plan.symbol}_${plan.quantity}_${addr}` }
-    } else {
-      if (!this.aster) throw new Error('Aster 适配器未配置')
-      const side = plan.side === 'buy' ? 'long' : 'short'
-      const res = await this.aster.openPerp({
-        symbol: plan.symbol,
-        side,
-        quantity: plan.quantity,
-        slippage: 0.005,
-        deadlineSec: Math.floor(Date.now() / 1000) + 300,
-      })
-      return res
-    }
-  }
-}
-
-export const tradeRouter = new TradeRouter()

+ 0 - 69
src/core/hedging/types.ts

@@ -1,69 +0,0 @@
-import { Position } from '../../types/core'
-
-export type HedgeMethod = 'spot' | 'perp'
-
-export interface HedgeThresholds {
-  maxSlippage: number // 允许最大滑点比例,如 0.005 = 0.5%
-  deltaDeviationPct: number // 允许的 delta 偏差百分比阈值
-  minFundingRate: number // 触发费率对冲的最小资金费率(绝对值)
-  minNotionalUSD: number // 执行最小名义金额(美元)
-}
-
-export interface FundingContext {
-  fundingRate: number // 当前资金费率(每8小时或每小时,统一成年化/周期化在调用处处理)
-  nextFundingTime?: number
-}
-
-export interface PriceContext {
-  perpPrice: number // Perp 市场价格(USD)
-  hedgePrice: number // 对冲工具价格(USD)
-  correlation: number // 相关系数(0-1)
-}
-
-export interface HedgeConfig {
-  preferredMethod: HedgeMethod // 首选对冲方式
-  thresholds: HedgeThresholds // 阈值控制
-}
-
-export interface HedgeDecision {
-  shouldHedge: boolean
-  method: HedgeMethod
-  hedgeQuantity: number // 对冲工具的数量(按 hedgePrice 标的)
-  reason: string
-  expectedFundingPnlPerPeriod?: number // 预计单周期资金费收益(USD)
-}
-
-export interface RouterQuote {
-  method: HedgeMethod
-  expectedIn?: number // 预期输入数量
-  expectedOut?: number // 预期输出数量
-  price: number // 用于滑点检查的价格
-  gasEstimateUSD?: number // 预估 gas 成本(USD)
-  slippage: number // 实际滑点
-  route?: string // 路由信息(演示)
-}
-
-export interface ExecutionPlan {
-  method: HedgeMethod
-  symbol: string
-  quantity: number // 对冲标的数量
-  side: 'buy' | 'sell' // 对冲方向
-  quote: RouterQuote
-}
-
-export interface ExecutionResult {
-  success: boolean
-  txHash?: string
-  orderId?: string | number
-  executedQuantity?: number
-  executedPrice?: number
-  error?: string
-}
-
-export interface HedgeRequest {
-  symbol: string // 如 BTCUSDT(perp 对)
-  perpPosition: Position // 当前 perp 仓位
-  prices: PriceContext // 价格上下文
-  funding: FundingContext // 资金费率上下文
-  config: HedgeConfig // 对冲配置
-}

+ 0 - 988
src/core/risk/controller.ts

@@ -1,988 +0,0 @@
-/**
- * 🎯 Delta中性控制器 v2.0 - 企业级Delta中性控制平面
- *
- * 基于tasks规范重构的核心控制器,支持:
- * - Delta中性自动维持(±0.0005 BTC阈值)
- * - 资金利用率控制(50%-80%目标范围)
- * - 多平台多账户管理和认证
- * - 企业级风险包络集成
- * - 8秒控制循环和紧急干预
- * - 智能对冲执行和市场条件检查
- */
-
-import { ExchangeAccount, ExchangeAccountConfig, AccountMetrics, DeltaControlParams } from '../models/ExchangeAccount'
-import {
-  RiskEnvelope,
-  RiskEnvelopeConfig,
-  RiskEnvelopeManager,
-  RiskMetrics,
-  ViolationEvent,
-} from '../models/RiskEnvelope'
-import UnifiedAccountManager from '../models/UnifiedAccountManager'
-import { TradingService, ServiceStatus, AccountState } from '../modules/types'
-import { logger } from '../shared/utils/logger'
-
-/**
- * Delta中性控制计划
- */
-export interface DeltaNeutralPlan {
-  planId: string
-  accountId: string
-  trigger: 'delta-threshold' | 'utilization-deviation' | 'emergency-hedge' | 'manual-control'
-  currentDelta: number
-  targetDelta: number
-  deltaThreshold: number
-  riskEnvelopeId: string
-  hedgeAccountId?: string
-  priority: 'low' | 'medium' | 'high' | 'critical'
-  maxExecutionTime: number
-  createdAt: Date
-}
-
-/**
- * 多平台认证策略
- */
-export interface MultiPlatformAuthStrategy {
-  exchange: 'pacifica' | 'aster' | 'binance'
-  authMethod: 'ed25519-signature' | 'eip191-signature' | 'hmac-sha256'
-  credentialValidation: (config: ExchangeAccountConfig) => boolean
-  proxyRequirement: boolean
-  sessionManagement: boolean
-}
-
-/**
- * 对冲执行请求
- */
-export interface HedgeExecutionRequest {
-  planId: string
-  primaryAccount: ExchangeAccount
-  hedgeAccount?: ExchangeAccount
-  symbol: string
-  hedgeSize: number
-  executionStrategy: 'market-orders' | 'limit-orders' | 'maker-taker-mixed'
-  riskEnvelope: RiskEnvelope
-  authStrategy: MultiPlatformAuthStrategy
-  proxyProfile?: string
-}
-
-/**
- * Delta中性控制执行结果
- */
-export interface DeltaNeutralExecutionResult {
-  planId: string
-  success: boolean
-  controlCycleId: string
-  accountId: string
-  deltaBefore: number
-  deltaAfter: number
-  utilizationBefore: number
-  utilizationAfter: number
-  hedgeExecuted: boolean
-  hedgeSize?: number
-  riskViolations: ViolationEvent[]
-  executionTimeMs: number
-  timestamp: Date
-  warnings: string[]
-  errors: string[]
-}
-
-/**
- * 控制循环状态
- */
-export interface ControlLoopState {
-  cycleId: string
-  isRunning: boolean
-  lastExecution: Date
-  nextExecution: Date
-  intervalMs: number
-  accountsMonitored: number
-  successfulCycles: number
-  failedCycles: number
-}
-
-/**
- * 资金利用率再平衡请求
- */
-export interface UtilizationRebalanceRequest {
-  accountId: string
-  targetUtilization: number
-  currentUtilization: number
-  preserveDeltaNeutrality: boolean
-  maxExecutionTime: number
-}
-
-/**
- * 资金利用率再平衡响应
- */
-export interface UtilizationRebalanceResponse {
-  success: boolean
-  utilizationBefore: number
-  utilizationAfter: number
-  deltaImpact: number
-  ordersExecuted: number
-  executionTime: number
-  warnings: string[]
-}
-
-type ServiceState =
-  | 'stopped'
-  | 'initializing'
-  | 'initialized'
-  | 'starting'
-  | 'running'
-  | 'stopping'
-  | 'error'
-  | 'emergency'
-
-/**
- * DeltaNeutralController v2.0 - Delta中性控制平面核心控制器
- *
- * 核心职责:
- * 1. 维持全局Delta中性(±0.0005 BTC阈值)
- * 2. 管理资金利用率(50%-80%目标范围)
- * 3. 集成风险包络系统
- * 4. 支持多平台多账户认证
- * 5. 8秒控制循环自动化
- * 6. 紧急干预和止损机制
- */
-export class DeltaNeutralController implements TradingService {
-  private status: ServiceState = 'stopped'
-  private lastStatusChange = Date.now()
-  private controlLoopState: ControlLoopState
-  private emergencyMode = false
-  private controlLoopInterval?: NodeJS.Timeout
-
-  // Delta中性控制配置
-  private readonly deltaControlConfig = {
-    deltaThreshold: 0.0005, // ±0.0005 BTC Delta阈值
-    utilizationTargetMin: 0.5, // 50% 最小利用率目标
-    utilizationTargetMax: 0.8, // 80% 最大利用率目标
-    controlCycleInterval: 8000, // 8秒控制循环
-    emergencyThreshold: 0.001, // 紧急对冲阈值(2倍Delta阈值)
-    maxHedgeSize: 0.1, // 最大单次对冲大小
-    maxExecutionTime: 30000, // 最大执行时间
-    riskCheckInterval: 5000, // 5秒风险检查间隔
-    emergencyStopLossTime: 30000, // 30秒紧急止损
-  }
-
-  // 多平台认证策略
-  private readonly authStrategies: Map<string, MultiPlatformAuthStrategy> = new Map([
-    [
-      'pacifica',
-      {
-        exchange: 'pacifica',
-        authMethod: 'ed25519-signature',
-        credentialValidation: config => !!config.privateKey && config.privateKey.length === 64,
-        proxyRequirement: true,
-        sessionManagement: false,
-      },
-    ],
-    [
-      'aster',
-      {
-        exchange: 'aster',
-        authMethod: 'eip191-signature',
-        credentialValidation: config => !!config.privateKey && config.privateKey.startsWith('0x'),
-        proxyRequirement: true,
-        sessionManagement: true,
-      },
-    ],
-    [
-      'binance',
-      {
-        exchange: 'binance',
-        authMethod: 'hmac-sha256',
-        credentialValidation: config => !!config.publicKey && !!config.privateKey,
-        proxyRequirement: false,
-        sessionManagement: false,
-      },
-    ],
-  ])
-
-  constructor(
-    private accountManager: UnifiedAccountManager,
-    private riskEnvelopeManager: RiskEnvelopeManager,
-  ) {
-    this.controlLoopState = {
-      cycleId: '',
-      isRunning: false,
-      lastExecution: new Date(),
-      nextExecution: new Date(),
-      intervalMs: this.deltaControlConfig.controlCycleInterval,
-      accountsMonitored: 0,
-      successfulCycles: 0,
-      failedCycles: 0,
-    }
-  }
-
-  /**
-   * 初始化Delta中性控制器
-   */
-  async initialize(): Promise<void> {
-    logger.info('🎯 DeltaNeutralController v2.0 初始化开始')
-    this.status = 'initializing'
-    this.lastStatusChange = Date.now()
-
-    try {
-      // 1. 验证多平台认证策略
-      await this.validateMultiPlatformAuth()
-
-      // 2. 初始化控制循环状态
-      this.controlLoopState = {
-        ...this.controlLoopState,
-        cycleId: `cycle-${Date.now()}`,
-        lastExecution: new Date(),
-        nextExecution: new Date(Date.now() + this.deltaControlConfig.controlCycleInterval),
-      }
-
-      // 3. 检查所有账户的Delta和利用率状态
-      await this.validateAccountStates()
-
-      // 4. 初始化风险包络系统
-      await this.initializeRiskEnvelopes()
-
-      this.status = 'initialized'
-      this.lastStatusChange = Date.now()
-      logger.info('✅ DeltaNeutralController v2.0 初始化完成')
-      logger.info(`📊 监控账户数: ${this.accountManager.getAllAccounts().length}`)
-      logger.info(`🎯 Delta阈值: ±${this.deltaControlConfig.deltaThreshold} BTC`)
-      logger.info(
-        `📈 利用率目标: ${this.deltaControlConfig.utilizationTargetMin * 100}-${
-          this.deltaControlConfig.utilizationTargetMax * 100
-        }%`,
-      )
-    } catch (error) {
-      this.status = 'error'
-      this.lastStatusChange = Date.now()
-      logger.error('❌ DeltaNeutralController 初始化失败:', error)
-      throw error
-    }
-  }
-
-  /**
-   * 启动Delta中性控制器
-   */
-  async start(): Promise<void> {
-    if (this.status !== 'initialized') {
-      throw new Error('DeltaNeutralController 必须先初始化')
-    }
-
-    logger.info('🚀 DeltaNeutralController v2.0 启动中')
-    this.status = 'starting'
-    this.lastStatusChange = Date.now()
-
-    try {
-      // 1. 执行启动前检查
-      await this.preStartupChecks()
-
-      // 2. 启动控制循环
-      this.startDeltaNeutralControlLoop()
-
-      // 3. 启动风险监控循环
-      this.startRiskMonitoringLoop()
-
-      this.status = 'running'
-      this.lastStatusChange = Date.now()
-      this.controlLoopState.isRunning = true
-
-      logger.info('✅ DeltaNeutralController v2.0 启动完成')
-      logger.info(`🔄 控制循环间隔: ${this.deltaControlConfig.controlCycleInterval}ms`)
-      logger.info(`🛡️ 风险检查间隔: ${this.deltaControlConfig.riskCheckInterval}ms`)
-      logger.info('🎯 Delta中性控制平面已激活')
-    } catch (error) {
-      this.status = 'error'
-      this.lastStatusChange = Date.now()
-      logger.error('❌ DeltaNeutralController 启动失败:', error)
-      throw error
-    }
-  }
-
-  /**
-   * 停止Delta中性控制器
-   */
-  async stop(): Promise<void> {
-    logger.info('🛑 DeltaNeutralController v2.0 停止中')
-    this.status = 'stopping'
-    this.lastStatusChange = Date.now()
-
-    try {
-      // 1. 停止所有控制循环
-      this.stopDeltaNeutralControlLoop()
-      this.stopRiskMonitoringLoop()
-
-      // 2. 执行紧急平仓(如果需要)
-      if (this.emergencyMode) {
-        await this.executeEmergencyShutdown()
-      }
-
-      // 3. 生成最终状态报告
-      await this.generateShutdownReport()
-
-      this.status = 'stopped'
-      this.lastStatusChange = Date.now()
-      this.controlLoopState.isRunning = false
-      this.emergencyMode = false
-
-      logger.info('✅ DeltaNeutralController v2.0 已安全停止')
-      logger.info(`📊 成功周期: ${this.controlLoopState.successfulCycles}`)
-      logger.info(`❌ 失败周期: ${this.controlLoopState.failedCycles}`)
-    } catch (error) {
-      this.status = 'error'
-      this.lastStatusChange = Date.now()
-      logger.error('❌ DeltaNeutralController 停止失败:', error)
-      throw error
-    }
-  }
-
-  /**
-   * 执行Delta中性控制计划
-   */
-  async executeDeltaNeutralPlan(plan: DeltaNeutralPlan): Promise<DeltaNeutralExecutionResult> {
-    const startTime = Date.now()
-    const controlCycleId = `cycle-${Date.now()}-${plan.accountId}`
-    logger.info(`🎯 [${controlCycleId}] 执行Delta中性控制计划`, {
-      accountId: plan.accountId,
-      trigger: plan.trigger,
-      currentDelta: plan.currentDelta,
-      targetDelta: plan.targetDelta,
-    })
-
-    try {
-      // 1. 获取账户和风险包络
-      const account = this.accountManager.getAccount(plan.accountId)
-      if (!account) {
-        throw new Error(`账户 ${plan.accountId} 未找到`)
-      }
-
-      const riskEnvelope = this.riskEnvelopeManager.getRiskEnvelope(plan.riskEnvelopeId)
-      if (!riskEnvelope) {
-        throw new Error(`风险包络 ${plan.riskEnvelopeId} 未找到`)
-      }
-
-      // 2. 执行风险预检查
-      const preCheckViolations = await this.performRiskPreCheck(account, riskEnvelope, plan)
-      if (preCheckViolations.length > 0) {
-        logger.warn(`🚨 [${controlCycleId}] 风险预检查发现违规`, { violations: preCheckViolations.length })
-      }
-
-      // 3. 获取当前状态指标
-      const metrics = account.getMetrics()
-      const deltaBefore = metrics.currentDelta
-      const utilizationBefore = metrics.currentUtilization
-
-      // 4. 判断是否需要执行对冲
-      const needsHedge = account.needsEmergencyHedge() || account.needsRebalance()
-      let hedgeExecuted = false
-      let hedgeSize = 0
-      let deltaAfter = deltaBefore
-      let utilizationAfter = utilizationBefore
-
-      if (needsHedge) {
-        // 5. 计算对冲大小
-        hedgeSize = account.calculateHedgeSize()
-
-        // 6. 执行对冲
-        const hedgeResult = await this.executeHedge(account, hedgeSize, plan, riskEnvelope)
-        hedgeExecuted = hedgeResult.success
-        deltaAfter = hedgeResult.deltaAfter
-        utilizationAfter = hedgeResult.utilizationAfter
-
-        // 7. 更新账户指标
-        account.updateMetrics({
-          currentDelta: deltaAfter,
-          currentUtilization: utilizationAfter,
-          lastUpdate: new Date(),
-        })
-      }
-
-      // 8. 执行风险后检查
-      const postCheckViolations = await this.performRiskPostCheck(account, riskEnvelope)
-
-      // 9. 生成执行结果
-      const result: DeltaNeutralExecutionResult = {
-        planId: plan.planId,
-        success: true,
-        controlCycleId,
-        accountId: plan.accountId,
-        deltaBefore,
-        deltaAfter,
-        utilizationBefore,
-        utilizationAfter,
-        hedgeExecuted,
-        hedgeSize: hedgeExecuted ? hedgeSize : undefined,
-        riskViolations: [...preCheckViolations, ...postCheckViolations],
-        executionTimeMs: Date.now() - startTime,
-        timestamp: new Date(),
-        warnings: [],
-        errors: [],
-      }
-
-      logger.info(`✅ [${controlCycleId}] Delta中性控制完成`, {
-        deltaChange: (deltaAfter - deltaBefore).toFixed(6),
-        utilizationChange: ((utilizationAfter - utilizationBefore) * 100).toFixed(1) + '%',
-        hedgeExecuted,
-        executionTime: result.executionTimeMs + 'ms',
-      })
-
-      return result
-    } catch (error) {
-      logger.error(`❌ [${controlCycleId}] Delta中性控制失败:`, error)
-
-      return {
-        planId: plan.planId,
-        success: false,
-        controlCycleId,
-        accountId: plan.accountId,
-        deltaBefore: plan.currentDelta,
-        deltaAfter: plan.currentDelta,
-        utilizationBefore: 0,
-        utilizationAfter: 0,
-        hedgeExecuted: false,
-        riskViolations: [],
-        executionTimeMs: Date.now() - startTime,
-        timestamp: new Date(),
-        warnings: [],
-        errors: [error instanceof Error ? error.message : String(error)],
-      }
-    }
-  }
-
-  /**
-   * 创建Delta中性控制计划
-   */
-  async createDeltaNeutralPlan(accountId: string, trigger: string): Promise<DeltaNeutralPlan> {
-    const account = this.accountManager.getAccount(accountId)
-    if (!account) {
-      throw new Error(`账户 ${accountId} 未找到`)
-    }
-
-    const metrics = account.getMetrics()
-    const config = account.getConfig()
-    const deltaParams = account.getDeltaParams()
-
-    const plan: DeltaNeutralPlan = {
-      planId: `plan-${Date.now()}-${accountId}`,
-      accountId,
-      trigger: trigger as any,
-      currentDelta: metrics.currentDelta,
-      targetDelta: deltaParams.targetDelta,
-      deltaThreshold: deltaParams.deltaThreshold,
-      riskEnvelopeId: `risk-${accountId}`, // 简化实现
-      priority: this.determinePriority(metrics.currentDelta, deltaParams.deltaThreshold),
-      maxExecutionTime: this.deltaControlConfig.maxExecutionTime,
-      createdAt: new Date(),
-    }
-
-    logger.info(`📋 [${plan.planId}] 创建Delta中性控制计划`, {
-      trigger: plan.trigger,
-      currentDelta: plan.currentDelta.toFixed(6),
-      priority: plan.priority,
-    })
-
-    return plan
-  }
-
-  /**
-   * 批量执行所有账户的Delta中性控制
-   */
-  async executeGlobalDeltaNeutralControl(): Promise<DeltaNeutralExecutionResult[]> {
-    const accounts = this.accountManager.getActiveAccounts()
-    const results: DeltaNeutralExecutionResult[] = []
-
-    logger.info(`🌐 执行全局Delta中性控制,监控 ${accounts.length} 个账户`)
-
-    for (const account of accounts) {
-      try {
-        const accountId = account.getConfig().accountId
-
-        // 检查是否需要控制
-        if (account.needsEmergencyHedge() || account.needsRebalance()) {
-          const trigger = account.needsEmergencyHedge() ? 'emergency-hedge' : 'utilization-deviation'
-          const plan = await this.createDeltaNeutralPlan(accountId, trigger)
-          const result = await this.executeDeltaNeutralPlan(plan)
-          results.push(result)
-
-          // 紧急模式检查
-          if (account.needsEmergencyHedge() && !result.success) {
-            logger.error(`🚨 账户 ${accountId} 紧急对冲失败,进入紧急模式`)
-            account.setEmergencyStatus(`紧急对冲失败: ${result.errors.join(', ')}`)
-            this.emergencyMode = true
-          }
-        }
-      } catch (error) {
-        logger.error(`账户 ${account.getConfig().accountId} 控制失败:`, error)
-      }
-    }
-
-    // 生成全局状态摘要
-    await this.logGlobalSystemSummary(results)
-
-    return results
-  }
-
-  /**
-   * 获取服务状态
-   */
-  getStatus(): ServiceStatus {
-    return {
-      name: 'DeltaNeutralController',
-      status: this.status === 'running' ? 'running' : this.status === 'error' ? 'error' : 'stopped',
-      lastUpdate: this.lastStatusChange,
-    }
-  }
-
-  getLastStatusChange(): number {
-    return this.lastStatusChange
-  }
-
-  /**
-   * 获取控制循环状态
-   */
-  getControlLoopState(): ControlLoopState {
-    return { ...this.controlLoopState }
-  }
-
-  /**
-   * 获取Delta控制配置
-   */
-  getDeltaControlConfig() {
-    return { ...this.deltaControlConfig }
-  }
-
-  /**
-   * 获取支持的认证策略
-   */
-  getSupportedAuthStrategies(): MultiPlatformAuthStrategy[] {
-    return Array.from(this.authStrategies.values())
-  }
-
-  /**
-   * 设置紧急模式
-   */
-  setEmergencyMode(enabled: boolean, reason?: string): void {
-    this.emergencyMode = enabled
-    if (enabled) {
-      this.status = 'emergency'
-      logger.error(`🚨 DeltaNeutralController 进入紧急模式: ${reason || '未知原因'}`)
-    } else {
-      this.status = 'running'
-      logger.info('✅ DeltaNeutralController 退出紧急模式')
-    }
-    this.lastStatusChange = Date.now()
-  }
-
-  // ========== 私有方法 ==========
-
-  private riskMonitoringInterval?: NodeJS.Timeout
-
-  /**
-   * 启动Delta中性控制循环
-   */
-  private startDeltaNeutralControlLoop(): void {
-    this.controlLoopInterval = setInterval(async () => {
-      try {
-        this.controlLoopState.cycleId = `cycle-${Date.now()}`
-        this.controlLoopState.lastExecution = new Date()
-        this.controlLoopState.nextExecution = new Date(Date.now() + this.deltaControlConfig.controlCycleInterval)
-
-        const results = await this.executeGlobalDeltaNeutralControl()
-
-        if (results.every(r => r.success)) {
-          this.controlLoopState.successfulCycles++
-        } else {
-          this.controlLoopState.failedCycles++
-        }
-      } catch (error) {
-        logger.error('❌ Delta中性控制循环失败:', error)
-        this.controlLoopState.failedCycles++
-      }
-    }, this.deltaControlConfig.controlCycleInterval)
-
-    logger.info(`🔄 Delta中性控制循环已启动,间隔 ${this.deltaControlConfig.controlCycleInterval}ms`)
-  }
-
-  /**
-   * 停止Delta中性控制循环
-   */
-  private stopDeltaNeutralControlLoop(): void {
-    if (this.controlLoopInterval) {
-      clearInterval(this.controlLoopInterval)
-      this.controlLoopInterval = undefined
-      logger.info('🛑 Delta中性控制循环已停止')
-    }
-  }
-
-  /**
-   * 启动风险监控循环
-   */
-  private startRiskMonitoringLoop(): void {
-    this.riskMonitoringInterval = setInterval(async () => {
-      try {
-        await this.performGlobalRiskCheck()
-      } catch (error) {
-        logger.error('❌ 风险监控循环失败:', error)
-      }
-    }, this.deltaControlConfig.riskCheckInterval)
-
-    logger.info(`🛡️ 风险监控循环已启动,间隔 ${this.deltaControlConfig.riskCheckInterval}ms`)
-  }
-
-  /**
-   * 停止风险监控循环
-   */
-  private stopRiskMonitoringLoop(): void {
-    if (this.riskMonitoringInterval) {
-      clearInterval(this.riskMonitoringInterval)
-      this.riskMonitoringInterval = undefined
-      logger.info('🛑 风险监控循环已停止')
-    }
-  }
-
-  /**
-   * 验证多平台认证策略
-   */
-  private async validateMultiPlatformAuth(): Promise<void> {
-    const accounts = this.accountManager.getAllAccounts()
-
-    for (const account of accounts) {
-      const config = account.getConfig()
-      const authStrategy = this.authStrategies.get(config.exchange)
-
-      if (!authStrategy) {
-        throw new Error(`不支持的交易所: ${config.exchange}`)
-      }
-
-      if (!authStrategy.credentialValidation(config)) {
-        throw new Error(`账户 ${config.accountId} 认证凭据验证失败`)
-      }
-    }
-
-    logger.info(`✅ 验证了 ${accounts.length} 个账户的多平台认证策略`)
-  }
-
-  /**
-   * 验证账户状态
-   */
-  private async validateAccountStates(): Promise<void> {
-    const accounts = this.accountManager.getAllAccounts()
-
-    for (const account of accounts) {
-      const metrics = account.getMetrics()
-      const config = account.getConfig()
-
-      // 检查基本状态
-      if (config.status !== 'active') {
-        logger.warn(`⚠️ 账户 ${config.accountId} 状态不是 active: ${config.status}`)
-      }
-
-      // 检查Delta阈值
-      if (Math.abs(metrics.currentDelta) > this.deltaControlConfig.emergencyThreshold) {
-        logger.warn(`🚨 账户 ${config.accountId} Delta超过紧急阈值: ${metrics.currentDelta}`)
-      }
-
-      // 检查利用率
-      if (
-        metrics.currentUtilization < this.deltaControlConfig.utilizationTargetMin ||
-        metrics.currentUtilization > this.deltaControlConfig.utilizationTargetMax
-      ) {
-        logger.warn(`⚠️ 账户 ${config.accountId} 利用率超出目标范围: ${(metrics.currentUtilization * 100).toFixed(1)}%`)
-      }
-    }
-
-    logger.info(`📊 验证了 ${accounts.length} 个账户的状态`)
-  }
-
-  /**
-   * 初始化风险包络系统
-   */
-  private async initializeRiskEnvelopes(): Promise<void> {
-    const accounts = this.accountManager.getAllAccounts()
-
-    for (const account of accounts) {
-      const config = account.getConfig()
-
-      // 检查是否已有风险包络
-      const existingEnvelope = this.riskEnvelopeManager.getRiskEnvelopeByAccount(config.accountId)
-
-      if (!existingEnvelope) {
-        // 创建默认风险包络
-        const riskConfig: RiskEnvelopeConfig = {
-          envelopeId: `risk-${config.accountId}`,
-          accountId: config.accountId,
-          maxDrawdownPercent: 5.0,
-          maxLeverage: 10.0,
-          maxPositionSize: config.maxPositionValue,
-          stopLossPercent: 3.0,
-          liquidationBuffer: 2.0,
-          riskBudgetUsd: config.maxPositionValue * 0.1,
-          enabled: true,
-        }
-
-        this.riskEnvelopeManager.createRiskEnvelope(riskConfig)
-        logger.info(`🛡️ 为账户 ${config.accountId} 创建默认风险包络`)
-      }
-    }
-  }
-
-  /**
-   * 执行启动前检查
-   */
-  private async preStartupChecks(): Promise<void> {
-    // 1. 检查紧急状态账户
-    const emergencyAccounts = this.accountManager
-      .getAllAccounts()
-      .filter(account => account.getConfig().status === 'emergency')
-
-    if (emergencyAccounts.length > 0) {
-      logger.warn(`⚠️ 发现 ${emergencyAccounts.length} 个紧急状态账户,将优先处理`)
-      this.emergencyMode = true
-    }
-
-    // 2. 检查全局Delta风险
-    const globalDelta = this.accountManager.calculateGlobalDelta()
-    if (Math.abs(globalDelta) > this.deltaControlConfig.emergencyThreshold) {
-      logger.warn(`🚨 全局Delta超过紧急阈值: ${globalDelta.toFixed(6)} BTC`)
-    }
-
-    // 3. 验证风险包络完整性
-    const accountsWithoutRisk = this.accountManager
-      .getAllAccounts()
-      .filter(account => !this.riskEnvelopeManager.getRiskEnvelopeByAccount(account.getConfig().accountId))
-
-    if (accountsWithoutRisk.length > 0) {
-      throw new Error(`${accountsWithoutRisk.length} 个账户缺少风险包络配置`)
-    }
-
-    logger.info('✅ 启动前检查通过')
-  }
-
-  /**
-   * 执行全局风险检查
-   */
-  private async performGlobalRiskCheck(): Promise<void> {
-    const accounts = this.accountManager.getAllAccounts()
-    let totalViolations = 0
-
-    for (const account of accounts) {
-      const riskEnvelope = this.riskEnvelopeManager.getRiskEnvelopeByAccount(account.getConfig().accountId)
-      if (riskEnvelope) {
-        const violations = riskEnvelope.checkViolations()
-        totalViolations += violations.length
-
-        if (violations.length > 0) {
-          logger.warn(`🛡️ 账户 ${account.getConfig().accountId} 发现 ${violations.length} 个风险违规`)
-        }
-      }
-    }
-
-    if (totalViolations > 0) {
-      logger.warn(`🚨 全局风险检查发现 ${totalViolations} 个违规事件`)
-    }
-  }
-
-  /**
-   * 执行风险预检查
-   */
-  private async performRiskPreCheck(
-    account: ExchangeAccount,
-    riskEnvelope: RiskEnvelope,
-    plan: DeltaNeutralPlan,
-  ): Promise<ViolationEvent[]> {
-    const violations: ViolationEvent[] = []
-    const metrics = account.getMetrics()
-
-    // 检查账户状态
-    if (account.getConfig().status !== 'active') {
-      violations.push({
-        violationId: `check-${Date.now()}-status`,
-        envelopeId: riskEnvelope.getConfig().envelopeId,
-        violationType: 'account-inactive',
-        severity: 'HIGH',
-        message: '账户状态不是活跃状态',
-        threshold: 'active',
-        actualValue: account.getConfig().status,
-        timestamp: new Date(),
-      })
-    }
-
-    // 检查Delta风险
-    if (Math.abs(metrics.currentDelta) > this.deltaControlConfig.emergencyThreshold) {
-      violations.push({
-        violationId: `check-${Date.now()}-delta`,
-        envelopeId: riskEnvelope.getConfig().envelopeId,
-        violationType: 'delta-emergency',
-        severity: 'CRITICAL',
-        message: 'Delta敞口超过紧急阈值',
-        threshold: this.deltaControlConfig.emergencyThreshold,
-        actualValue: Math.abs(metrics.currentDelta),
-        timestamp: new Date(),
-      })
-    }
-
-    return violations
-  }
-
-  /**
-   * 执行风险后检查
-   */
-  private async performRiskPostCheck(account: ExchangeAccount, riskEnvelope: RiskEnvelope): Promise<ViolationEvent[]> {
-    // 更新风险包络指标
-    const metrics = account.getMetrics()
-    riskEnvelope.updateMetrics({
-      currentDrawdown: 0, // 需要计算
-      currentLeverage: metrics.leverage || 1,
-      currentPositionSize: Math.abs(metrics.netPosition),
-      dailyPnl: metrics.unrealizedPnl || 0,
-      riskScore: 0, // 会自动计算
-    })
-
-    // 检查违规
-    return riskEnvelope.checkViolations()
-  }
-
-  /**
-   * 执行对冲
-   */
-  private async executeHedge(
-    account: ExchangeAccount,
-    hedgeSize: number,
-    plan: DeltaNeutralPlan,
-    riskEnvelope: RiskEnvelope,
-  ): Promise<{ success: boolean; deltaAfter: number; utilizationAfter: number }> {
-    const config = account.getConfig()
-    const authStrategy = this.authStrategies.get(config.exchange)
-
-    if (!authStrategy) {
-      throw new Error(`不支持的交易所认证: ${config.exchange}`)
-    }
-
-    logger.info(`🔄 执行对冲`, {
-      accountId: config.accountId,
-      exchange: config.exchange,
-      hedgeSize: hedgeSize.toFixed(6),
-      authMethod: authStrategy.authMethod,
-    })
-
-    try {
-      // 模拟对冲执行(实际实现需要调用交易接口)
-      const deltaAfter = account.getMetrics().currentDelta - hedgeSize
-      const utilizationAdjustment = account.calculateUtilizationAdjustment()
-      const utilizationAfter = account.getMetrics().currentUtilization + utilizationAdjustment
-
-      // 记录对冲历史
-      logger.info(`✅ 对冲执行完成`, {
-        accountId: config.accountId,
-        deltaChange: (-hedgeSize).toFixed(6),
-        deltaAfter: deltaAfter.toFixed(6),
-        utilizationAfter: (utilizationAfter * 100).toFixed(1) + '%',
-      })
-
-      return {
-        success: true,
-        deltaAfter,
-        utilizationAfter,
-      }
-    } catch (error) {
-      logger.error(`❌ 对冲执行失败:`, error)
-      return {
-        success: false,
-        deltaAfter: account.getMetrics().currentDelta,
-        utilizationAfter: account.getMetrics().currentUtilization,
-      }
-    }
-  }
-
-  /**
-   * 确定计划优先级
-   */
-  private determinePriority(currentDelta: number, deltaThreshold: number): 'low' | 'medium' | 'high' | 'critical' {
-    const deltaRatio = Math.abs(currentDelta) / deltaThreshold
-
-    if (deltaRatio >= 2.0) return 'critical'
-    if (deltaRatio >= 1.5) return 'high'
-    if (deltaRatio >= 1.0) return 'medium'
-    return 'low'
-  }
-
-  /**
-   * 生成全局系统摘要日志
-   */
-  private async logGlobalSystemSummary(results: DeltaNeutralExecutionResult[]): Promise<void> {
-    const totalAccounts = this.accountManager.getAllAccounts().length
-    const activeAccounts = this.accountManager.getActiveAccounts().length
-    const needingHedge = this.accountManager.getAccountsNeedingHedge().length
-    const globalDelta = this.accountManager.calculateGlobalDelta()
-    const globalUtilization = this.accountManager.calculateGlobalUtilization()
-
-    const successfulExecutions = results.filter(r => r.success).length
-    const failedExecutions = results.filter(r => !r.success).length
-    const totalViolations = results.reduce((sum, r) => sum + r.riskViolations.length, 0)
-
-    logger.info('📊 全局Delta中性控制摘要', {
-      accounts: {
-        total: totalAccounts,
-        active: activeAccounts,
-        needingHedge: needingHedge,
-      },
-      global: {
-        delta: globalDelta.toFixed(6) + ' BTC',
-        utilization: (globalUtilization * 100).toFixed(1) + '%',
-      },
-      execution: {
-        successful: successfulExecutions,
-        failed: failedExecutions,
-        riskViolations: totalViolations,
-      },
-      controlLoop: {
-        cycleId: this.controlLoopState.cycleId,
-        successfulCycles: this.controlLoopState.successfulCycles,
-        failedCycles: this.controlLoopState.failedCycles,
-      },
-      emergencyMode: this.emergencyMode,
-    })
-  }
-
-  /**
-   * 执行紧急关闭
-   */
-  private async executeEmergencyShutdown(): Promise<void> {
-    logger.error('🚨 执行紧急关闭程序')
-
-    const emergencyAccounts = this.accountManager
-      .getAllAccounts()
-      .filter(account => account.getConfig().status === 'emergency')
-
-    for (const account of emergencyAccounts) {
-      try {
-        // 执行紧急平仓(简化实现)
-        account.resetToActive()
-        logger.info(`✅ 账户 ${account.getConfig().accountId} 紧急处理完成`)
-      } catch (error) {
-        logger.error(`❌ 账户 ${account.getConfig().accountId} 紧急处理失败:`, error)
-      }
-    }
-  }
-
-  /**
-   * 生成关闭报告
-   */
-  private async generateShutdownReport(): Promise<void> {
-    const systemSummary = this.accountManager.getSystemSummary()
-
-    logger.info('📋 DeltaNeutralController 关闭报告', {
-      runtime: {
-        successfulCycles: this.controlLoopState.successfulCycles,
-        failedCycles: this.controlLoopState.failedCycles,
-        totalCycles: this.controlLoopState.successfulCycles + this.controlLoopState.failedCycles,
-      },
-      finalState: {
-        totalAccounts: systemSummary.totalAccounts,
-        activeAccounts: systemSummary.activeAccounts,
-        accountsNeedingHedge: systemSummary.accountsNeedingHedge,
-        globalDelta: systemSummary.globalDelta.toFixed(6) + ' BTC',
-        globalUtilization: (systemSummary.globalUtilization * 100).toFixed(1) + '%',
-      },
-      emergencyMode: this.emergencyMode,
-    })
-  }
-}

+ 0 - 652
src/core/risk/envelope.ts

@@ -1,652 +0,0 @@
-/**
- * 🛡️ RiskEnvelope - Delta中性控制平面风险包络模型
- *
- * 按照tasks规范实现的风险包络系统,支持:
- * - 每账户独立风险边界
- * - 动态风险参数调整
- * - 多维度风险监控
- * - 紧急风险响应
- * - 与Delta控制深度集成
- */
-export interface RiskEnvelopeConfig {
-  envelopeId: string // 主键,唯一标识
-  accountId: string // 外键,关联ExchangeAccount
-  maxDrawdownPercent: number // 最大回撤百分比
-  maxLeverage: number // 最大杠杆倍数
-  deltaThreshold?: number // Delta阈值(可覆盖账户级设定)
-  slippageTolerance: number // 滑点容忍度(百分比)
-  maxOrderSize: number // 单笔订单最大大小
-  maxDailyVolume: number // 日最大交易量
-  emergencyLiquidationThreshold: number // 紧急清算阈值
-  createdAt?: Date
-  updatedAt?: Date
-}
-
-export interface RiskMetrics {
-  currentDrawdown: number // 当前回撤
-  currentLeverage: number // 当前杠杆
-  currentSlippage: number // 当前滑点
-  dailyVolume: number // 今日交易量
-  riskScore: number // 综合风险评分 (0-100)
-  healthStatus: 'healthy' | 'warning' | 'critical' | 'emergency'
-  lastUpdate: Date
-}
-
-export interface ViolationEvent {
-  id: string
-  type: 'drawdown' | 'leverage' | 'delta' | 'slippage' | 'volume' | 'emergency'
-  severity: 'low' | 'medium' | 'high' | 'critical'
-  threshold: number // 阈值
-  actual: number // 实际值
-  message: string
-  timestamp: Date
-  resolved: boolean
-  resolvedAt?: Date
-}
-
-/**
- * RiskEnvelope - 账户风险包络实体
- */
-export class RiskEnvelope {
-  private config: RiskEnvelopeConfig
-  private metrics: RiskMetrics
-  private violations: ViolationEvent[] = []
-  private emergencyMode = false
-  private lastCheck: Date = new Date()
-  private riskHistory: Array<{ time: Date; score: number; status: string }> = []
-
-  constructor(config: RiskEnvelopeConfig) {
-    this.config = { ...config }
-    this.validateConfig()
-    this.initializeMetrics()
-  }
-
-  /**
-   * 验证风险包络配置
-   */
-  private validateConfig(): void {
-    if (!this.config.envelopeId) {
-      throw new Error('RiskEnvelope: envelopeId is required')
-    }
-    if (!this.config.accountId) {
-      throw new Error('RiskEnvelope: accountId is required')
-    }
-    if (this.config.maxDrawdownPercent <= 0 || this.config.maxDrawdownPercent > 1) {
-      throw new Error('RiskEnvelope: maxDrawdownPercent must be between 0 and 1')
-    }
-    if (this.config.maxLeverage <= 0) {
-      throw new Error('RiskEnvelope: maxLeverage must be positive')
-    }
-    if (this.config.slippageTolerance < 0 || this.config.slippageTolerance > 1) {
-      throw new Error('RiskEnvelope: slippageTolerance must be between 0 and 1')
-    }
-  }
-
-  /**
-   * 初始化风险指标
-   */
-  private initializeMetrics(): void {
-    this.metrics = {
-      currentDrawdown: 0,
-      currentLeverage: 1,
-      currentSlippage: 0,
-      dailyVolume: 0,
-      riskScore: 0,
-      healthStatus: 'healthy',
-      lastUpdate: new Date(),
-    }
-  }
-
-  /**
-   * 更新风险指标
-   */
-  updateMetrics(newMetrics: Partial<RiskMetrics>): void {
-    this.metrics = {
-      ...this.metrics,
-      ...newMetrics,
-      lastUpdate: new Date(),
-    }
-
-    // 重新计算风险评分
-    this.calculateRiskScore()
-
-    // 检查风险违规
-    this.checkViolations()
-
-    // 记录风险历史
-    this.recordRiskHistory()
-  }
-
-  /**
-   * 计算综合风险评分 (0-100)
-   */
-  private calculateRiskScore(): void {
-    let score = 0
-
-    // 回撤风险 (0-30分)
-    const drawdownRatio = this.metrics.currentDrawdown / this.config.maxDrawdownPercent
-    score += Math.min(drawdownRatio * 30, 30)
-
-    // 杠杆风险 (0-25分)
-    const leverageRatio = this.metrics.currentLeverage / this.config.maxLeverage
-    score += Math.min(leverageRatio * 25, 25)
-
-    // 滑点风险 (0-20分)
-    const slippageRatio = this.metrics.currentSlippage / this.config.slippageTolerance
-    score += Math.min(slippageRatio * 20, 20)
-
-    // 交易量风险 (0-15分)
-    const volumeRatio = this.metrics.dailyVolume / this.config.maxDailyVolume
-    score += Math.min(volumeRatio * 15, 15)
-
-    // 紧急模式额外风险 (0-10分)
-    if (this.emergencyMode) {
-      score += 10
-    }
-
-    this.metrics.riskScore = Math.min(score, 100)
-
-    // 更新健康状态
-    this.updateHealthStatus()
-  }
-
-  /**
-   * 更新健康状态
-   */
-  private updateHealthStatus(): void {
-    if (this.emergencyMode || this.metrics.riskScore >= 90) {
-      this.metrics.healthStatus = 'emergency'
-    } else if (this.metrics.riskScore >= 70) {
-      this.metrics.healthStatus = 'critical'
-    } else if (this.metrics.riskScore >= 40) {
-      this.metrics.healthStatus = 'warning'
-    } else {
-      this.metrics.healthStatus = 'healthy'
-    }
-  }
-
-  /**
-   * 检查风险违规
-   */
-  private checkViolations(): void {
-    // 检查回撤违规
-    if (this.metrics.currentDrawdown > this.config.maxDrawdownPercent) {
-      this.addViolation(
-        'drawdown',
-        'critical',
-        this.config.maxDrawdownPercent,
-        this.metrics.currentDrawdown,
-        `回撤超过限制: ${(this.metrics.currentDrawdown * 100).toFixed(2)}% > ${(
-          this.config.maxDrawdownPercent * 100
-        ).toFixed(2)}%`,
-      )
-    }
-
-    // 检查杠杆违规
-    if (this.metrics.currentLeverage > this.config.maxLeverage) {
-      this.addViolation(
-        'leverage',
-        'high',
-        this.config.maxLeverage,
-        this.metrics.currentLeverage,
-        `杠杆超过限制: ${this.metrics.currentLeverage.toFixed(2)}x > ${this.config.maxLeverage.toFixed(2)}x`,
-      )
-    }
-
-    // 检查滑点违规
-    if (this.metrics.currentSlippage > this.config.slippageTolerance) {
-      this.addViolation(
-        'slippage',
-        'medium',
-        this.config.slippageTolerance,
-        this.metrics.currentSlippage,
-        `滑点超过容忍度: ${(this.metrics.currentSlippage * 100).toFixed(2)}% > ${(
-          this.config.slippageTolerance * 100
-        ).toFixed(2)}%`,
-      )
-    }
-
-    // 检查交易量违规
-    if (this.metrics.dailyVolume > this.config.maxDailyVolume) {
-      this.addViolation(
-        'volume',
-        'medium',
-        this.config.maxDailyVolume,
-        this.metrics.dailyVolume,
-        `日交易量超过限制: ${this.metrics.dailyVolume.toFixed(2)} > ${this.config.maxDailyVolume.toFixed(2)}`,
-      )
-    }
-
-    // 检查紧急清算阈值
-    if (this.metrics.currentDrawdown >= this.config.emergencyLiquidationThreshold) {
-      this.addViolation(
-        'emergency',
-        'critical',
-        this.config.emergencyLiquidationThreshold,
-        this.metrics.currentDrawdown,
-        `触发紧急清算阈值: ${(this.metrics.currentDrawdown * 100).toFixed(2)}%`,
-      )
-      this.triggerEmergencyMode('达到紧急清算阈值')
-    }
-  }
-
-  /**
-   * 添加违规事件
-   */
-  private addViolation(
-    type: ViolationEvent['type'],
-    severity: ViolationEvent['severity'],
-    threshold: number,
-    actual: number,
-    message: string,
-  ): void {
-    const violation: ViolationEvent = {
-      id: `${this.config.envelopeId}-${type}-${Date.now()}`,
-      type,
-      severity,
-      threshold,
-      actual,
-      message,
-      timestamp: new Date(),
-      resolved: false,
-    }
-
-    this.violations.push(violation)
-
-    console.log(`🚨 [RiskEnvelope:${this.config.accountId}] ${severity.toUpperCase()}: ${message}`)
-
-    // 保留最近100条违规记录
-    if (this.violations.length > 100) {
-      this.violations = this.violations.slice(-100)
-    }
-  }
-
-  /**
-   * 记录风险历史
-   */
-  private recordRiskHistory(): void {
-    this.riskHistory.push({
-      time: new Date(),
-      score: this.metrics.riskScore,
-      status: this.metrics.healthStatus,
-    })
-
-    // 保留最近200条记录
-    if (this.riskHistory.length > 200) {
-      this.riskHistory = this.riskHistory.slice(-200)
-    }
-  }
-
-  /**
-   * 触发紧急模式
-   */
-  triggerEmergencyMode(reason: string): void {
-    this.emergencyMode = true
-    this.metrics.healthStatus = 'emergency'
-    console.log(`🚨 [RiskEnvelope:${this.config.accountId}] 进入紧急模式: ${reason}`)
-
-    this.addViolation('emergency', 'critical', 0, 1, `紧急模式激活: ${reason}`)
-  }
-
-  /**
-   * 重置紧急模式
-   */
-  resetEmergencyMode(): void {
-    this.emergencyMode = false
-    console.log(`✅ [RiskEnvelope:${this.config.accountId}] 退出紧急模式`)
-
-    // 标记最新的紧急违规为已解决
-    const latestEmergencyViolation = this.violations.filter(v => v.type === 'emergency' && !v.resolved).pop()
-
-    if (latestEmergencyViolation) {
-      latestEmergencyViolation.resolved = true
-      latestEmergencyViolation.resolvedAt = new Date()
-    }
-
-    // 重新计算风险评分
-    this.calculateRiskScore()
-  }
-
-  /**
-   * 检查是否可以执行交易
-   */
-  canExecuteTrade(
-    orderSize: number,
-    orderType: 'market' | 'limit',
-  ): {
-    allowed: boolean
-    reason?: string
-    maxAllowedSize?: number
-  } {
-    // 紧急模式下禁止新交易
-    if (this.emergencyMode) {
-      return { allowed: false, reason: '紧急模式下禁止交易' }
-    }
-
-    // 检查健康状态
-    if (this.metrics.healthStatus === 'emergency') {
-      return { allowed: false, reason: '风险状态为emergency,禁止交易' }
-    }
-
-    // 检查订单大小限制
-    if (orderSize > this.config.maxOrderSize) {
-      return {
-        allowed: false,
-        reason: `订单大小超过限制: ${orderSize} > ${this.config.maxOrderSize}`,
-        maxAllowedSize: this.config.maxOrderSize,
-      }
-    }
-
-    // 检查日交易量限制
-    const remainingVolume = this.config.maxDailyVolume - this.metrics.dailyVolume
-    if (orderSize > remainingVolume) {
-      return {
-        allowed: false,
-        reason: `超过日交易量限制,剩余: ${remainingVolume.toFixed(2)}`,
-        maxAllowedSize: remainingVolume,
-      }
-    }
-
-    // 风险评分过高时限制市价单
-    if (orderType === 'market' && this.metrics.riskScore > 80) {
-      return { allowed: false, reason: '风险评分过高,禁止市价单交易' }
-    }
-
-    return { allowed: true }
-  }
-
-  /**
-   * 获取配置
-   */
-  getConfig(): RiskEnvelopeConfig {
-    return { ...this.config }
-  }
-
-  /**
-   * 获取当前指标
-   */
-  getMetrics(): RiskMetrics {
-    return { ...this.metrics }
-  }
-
-  /**
-   * 获取活跃违规
-   */
-  getActiveViolations(): ViolationEvent[] {
-    return this.violations.filter(v => !v.resolved)
-  }
-
-  /**
-   * 获取风险历史
-   */
-  getRiskHistory(): Array<{ time: Date; score: number; status: string }> {
-    return [...this.riskHistory]
-  }
-
-  /**
-   * 是否处于紧急模式
-   */
-  isEmergencyMode(): boolean {
-    return this.emergencyMode
-  }
-
-  /**
-   * 获取风险包络摘要
-   */
-  getSummary(): any {
-    return {
-      envelopeId: this.config.envelopeId,
-      accountId: this.config.accountId,
-      riskScore: this.metrics.riskScore,
-      healthStatus: this.metrics.healthStatus,
-      emergencyMode: this.emergencyMode,
-      activeViolations: this.getActiveViolations().length,
-      limits: {
-        maxDrawdown: `${(this.config.maxDrawdownPercent * 100).toFixed(1)}%`,
-        maxLeverage: `${this.config.maxLeverage.toFixed(1)}x`,
-        maxSlippage: `${(this.config.slippageTolerance * 100).toFixed(1)}%`,
-        maxOrderSize: this.config.maxOrderSize,
-        maxDailyVolume: this.config.maxDailyVolume,
-      },
-      current: {
-        drawdown: `${(this.metrics.currentDrawdown * 100).toFixed(2)}%`,
-        leverage: `${this.metrics.currentLeverage.toFixed(2)}x`,
-        slippage: `${(this.metrics.currentSlippage * 100).toFixed(2)}%`,
-        dailyVolume: this.metrics.dailyVolume.toFixed(2),
-      },
-      lastUpdate: this.metrics.lastUpdate,
-    }
-  }
-}
-
-/**
- * 风险指标
- */
-export interface RiskMetrics {
-  envelopeId: string
-  accountId: string
-  currentDelta: number // BTC 等值
-  deltaDeviation: number // 偏离目标的程度
-  currentUtilization: number // 当前利用率
-  maxUtilization: number // 历史最大利用率
-  currentDrawdown: number // 当前回撤
-  maxDrawdown: number // 历史最大回撤
-  currentLeverage: number // 当前杠杆
-  maxLeverage: number // 历史最大杠杆
-  slippage: number // 当前滑点
-  positionValue: number // 当前仓位价值
-  availableBalance: number // 可用余额
-  totalBalance: number // 总余额
-  timestamp: Date
-}
-
-/**
- * 风险警报
- */
-export interface RiskAlert {
-  alertId: string
-  envelopeId: string
-  accountId: string
-  type:
-    | 'delta-breach'
-    | 'utilization-high'
-    | 'utilization-low'
-    | 'drawdown-exceeded'
-    | 'leverage-exceeded'
-    | 'slippage-high'
-  severity: 'INFO' | 'WARN' | 'CRITICAL'
-  message: string
-  currentValue: number
-  threshold: number
-  deviation: number
-  timestamp: Date
-  acknowledged: boolean
-  resolved: boolean
-}
-
-/**
- * 风险控制动作
- */
-export interface RiskControlAction {
-  actionId: string
-  envelopeId: string
-  accountId: string
-  triggerAlertId: string
-  actionType: 'hedge' | 'reduce-position' | 'emergency-stop' | 'halt-trading'
-  description: string
-  parameters: Record<string, any>
-  status: 'pending' | 'executing' | 'completed' | 'failed'
-  createdAt: Date
-  completedAt?: Date
-  error?: string
-}
-
-import { TradingService, ServiceStatus } from '../modules/types'
-import { logger } from '../shared/utils/logger'
-
-/**
- * RiskEnvelopeManager - 管理多个风险包络
- */
-export class RiskEnvelopeManager implements TradingService {
-  private status: 'stopped' | 'initializing' | 'running' | 'stopping' | 'error' = 'stopped'
-  private lastStatusChange = Date.now()
-  private envelopes: Map<string, RiskEnvelope> = new Map()
-  private globalRiskLimits = {
-    maxSystemRiskScore: 75,
-    maxEmergencyAccounts: 2,
-    maxCriticalAccounts: 5,
-  }
-
-  async initialize(): Promise<void> {
-    logger.info('RiskEnvelopeManager初始化')
-    this.status = 'running'
-    this.lastStatusChange = Date.now()
-  }
-
-  async start(): Promise<void> {
-    logger.info('RiskEnvelopeManager启动')
-  }
-
-  async stop(): Promise<void> {
-    logger.info('RiskEnvelopeManager停止')
-    this.status = 'stopped'
-    this.lastStatusChange = Date.now()
-  }
-
-  getStatus(): ServiceStatus {
-    return {
-      name: 'RiskEnvelopeManager',
-      status: this.status === 'running' ? 'running' : 'stopped',
-      lastUpdate: this.lastStatusChange,
-    }
-  }
-
-  getLastStatusChange(): number {
-    return this.lastStatusChange
-  }
-
-  /**
-   * 创建风险包络
-   */
-  createRiskEnvelope(config: RiskEnvelopeConfig): RiskEnvelope {
-    const envelope = new RiskEnvelope(config)
-    this.envelopes.set(config.envelopeId, envelope)
-    logger.info(`✅ [RiskEnvelopeManager] 创建风险包络: ${config.envelopeId} (账户: ${config.accountId})`)
-    return envelope
-  }
-
-  /**
-   * 添加风险包络
-   */
-  addEnvelope(config: RiskEnvelopeConfig): RiskEnvelope {
-    const envelope = new RiskEnvelope(config)
-    this.envelopes.set(config.envelopeId, envelope)
-    console.log(`✅ [RiskEnvelopeManager] 添加风险包络: ${config.envelopeId} (账户: ${config.accountId})`)
-    return envelope
-  }
-
-  /**
-   * 获取风险包络
-   */
-  getRiskEnvelope(envelopeId: string): RiskEnvelope | undefined {
-    return this.envelopes.get(envelopeId)
-  }
-
-  /**
-   * 获取风险包络
-   */
-  getEnvelope(envelopeId: string): RiskEnvelope | undefined {
-    return this.envelopes.get(envelopeId)
-  }
-
-  /**
-   * 根据账户ID获取风险包络
-   */
-  getRiskEnvelopeByAccount(accountId: string): RiskEnvelope | undefined {
-    for (const envelope of this.envelopes.values()) {
-      if (envelope.getConfig().accountId === accountId) {
-        return envelope
-      }
-    }
-    return undefined
-  }
-
-  /**
-   * 根据账户ID获取风险包络
-   */
-  getEnvelopeByAccount(accountId: string): RiskEnvelope | undefined {
-    for (const envelope of this.envelopes.values()) {
-      if (envelope.getConfig().accountId === accountId) {
-        return envelope
-      }
-    }
-    return undefined
-  }
-
-  /**
-   * 获取所有风险包络
-   */
-  getAllEnvelopes(): RiskEnvelope[] {
-    return Array.from(this.envelopes.values())
-  }
-
-  /**
-   * 获取系统风险摘要
-   */
-  getSystemRiskSummary(): any {
-    const envelopes = this.getAllEnvelopes()
-    const systemRiskScore = this.calculateSystemRiskScore()
-
-    const statusCounts = {
-      healthy: 0,
-      warning: 0,
-      critical: 0,
-      emergency: 0,
-    }
-
-    envelopes.forEach(envelope => {
-      const status = envelope.getMetrics().healthStatus
-      statusCounts[status]++
-    })
-
-    return {
-      totalEnvelopes: envelopes.length,
-      systemRiskScore,
-      statusCounts,
-      globalLimits: this.globalRiskLimits,
-      systemHealthy:
-        systemRiskScore < this.globalRiskLimits.maxSystemRiskScore &&
-        statusCounts.emergency <= this.globalRiskLimits.maxEmergencyAccounts &&
-        statusCounts.critical <= this.globalRiskLimits.maxCriticalAccounts,
-      envelopes: envelopes.map(env => env.getSummary()),
-    }
-  }
-
-  /**
-   * 计算系统风险评分
-   */
-  private calculateSystemRiskScore(): number {
-    const envelopes = this.getAllEnvelopes()
-    if (envelopes.length === 0) return 0
-
-    const totalRiskScore = envelopes.reduce((sum, env) => sum + env.getMetrics().riskScore, 0)
-    return totalRiskScore / envelopes.length
-  }
-
-  /**
-   * 检查系统是否可以执行交易
-   */
-  canSystemExecuteTrade(): { allowed: boolean; reason?: string } {
-    const summary = this.getSystemRiskSummary()
-
-    if (!summary.systemHealthy) {
-      return { allowed: false, reason: '系统风险过高,暂停交易' }
-    }
-
-    if (summary.statusCounts.emergency > 0) {
-      return { allowed: false, reason: '存在紧急状态账户,暂停系统交易' }
-    }
-
-    return { allowed: true }
-  }
-}