Spaces:
Paused
Paused
icebear0828 Claude Opus 4.6 commited on
Commit ·
92c5df7
1
Parent(s): ab2754a
feat: OpenCode platform support, vitest tests, changelog & Docker hardening
Browse files- Add opencode.json provider config for OpenCode IDE integration
- Add CHANGELOG.md covering all versions (v0.1.0–v0.8.0)
- Add vitest with unit tests for account-pool, codex-api, codex-event-extractor
- Add request-id middleware to global middleware chain
- Harden Dockerfile: non-root user, HEALTHCHECK probe
- Simplify /health endpoint to return pool summary only
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CHANGELOG.md +142 -0
- Dockerfile +8 -0
- opencode.json +23 -0
- package-lock.json +1091 -20
- package.json +4 -1
- src/auth/__tests__/account-pool.test.ts +292 -0
- src/index.ts +2 -0
- src/proxy/__tests__/codex-api.test.ts +201 -0
- src/routes/web.ts +1 -5
- src/translation/__tests__/codex-event-extractor.test.ts +182 -0
- vitest.config.ts +8 -0
CHANGELOG.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Changelog
|
| 2 |
+
|
| 3 |
+
本项目的所有重要变更都将记录在此文件中。
|
| 4 |
+
|
| 5 |
+
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/)。
|
| 6 |
+
|
| 7 |
+
## [Unreleased]
|
| 8 |
+
|
| 9 |
+
### Added
|
| 10 |
+
|
| 11 |
+
- OpenCode 平台支持(`opencode.json` 配置文件)
|
| 12 |
+
- Vitest 测试框架(account-pool、codex-api、codex-event-extractor 单元测试)
|
| 13 |
+
- request-id 中间件注入全局请求链路 ID
|
| 14 |
+
- Dockerfile 安全加固(非 root 用户运行、HEALTHCHECK 探针)
|
| 15 |
+
|
| 16 |
+
### Changed
|
| 17 |
+
|
| 18 |
+
- `/health` 端点精简,仅返回 pool 摘要(total / active)
|
| 19 |
+
|
| 20 |
+
## [v0.8.0](https://github.com/icebear0828/codex-proxy/releases/tag/v0.8.0) - 2026-02-24
|
| 21 |
+
|
| 22 |
+
### Added
|
| 23 |
+
|
| 24 |
+
- 原生 function_call / tool_calls 支持(所有协议)
|
| 25 |
+
|
| 26 |
+
### Fixed
|
| 27 |
+
|
| 28 |
+
- 格式错误的 chat payload 返回 400 `invalid_json` 错误
|
| 29 |
+
|
| 30 |
+
## [v0.7.0](https://github.com/icebear0828/codex-proxy/releases/tag/v0.7.0) - 2026-02-22
|
| 31 |
+
|
| 32 |
+
### Added
|
| 33 |
+
|
| 34 |
+
- `developer` 角色支持(OpenAI 协议)
|
| 35 |
+
- 数组格式 content 支持
|
| 36 |
+
- tool / function 消息兼容(所有协议)
|
| 37 |
+
- 模型响应中自动过滤 Codex Desktop 指令
|
| 38 |
+
|
| 39 |
+
### Changed
|
| 40 |
+
|
| 41 |
+
- 清理无用代码、未使用配置,修复类型违规
|
| 42 |
+
|
| 43 |
+
### Fixed
|
| 44 |
+
|
| 45 |
+
- 启动日志显示配置的 `proxy_api_key` 而非随机哈希
|
| 46 |
+
- 首次 OAuth 登录后 `useStatus` 未刷新
|
| 47 |
+
|
| 48 |
+
## [v0.6.0](https://github.com/icebear0828/codex-proxy/releases/tag/v0.6.0) - 2026-02-21
|
| 49 |
+
|
| 50 |
+
### Added
|
| 51 |
+
|
| 52 |
+
- libcurl-impersonate FFI 传输层,Chrome TLS 指纹
|
| 53 |
+
- pnpm / bun 包管理器支持
|
| 54 |
+
|
| 55 |
+
### Changed
|
| 56 |
+
|
| 57 |
+
- README 快速开始按平台重组
|
| 58 |
+
|
| 59 |
+
### Fixed
|
| 60 |
+
|
| 61 |
+
- Docker 构建完整修复链(代理配置、BuildKit 冲突、host 网络、源码复制顺序、layer 优化)
|
| 62 |
+
- `.env` 行内注释被误解析为 JWT token
|
| 63 |
+
- Anthropic / Gemini 代码示例跟随所选模型
|
| 64 |
+
- `proxy_api_key` 配置未在前端和认证验证中使用
|
| 65 |
+
- 删除按钮始终可见,不被状态徽章遮挡
|
| 66 |
+
|
| 67 |
+
## [v0.5.0](https://github.com/icebear0828/codex-proxy/releases/tag/v0.5.0) - 2026-02-20
|
| 68 |
+
|
| 69 |
+
### Added
|
| 70 |
+
|
| 71 |
+
- Dashboard 暗色 / 亮色主题切换
|
| 72 |
+
- 国际化支持(中文 / 英文)
|
| 73 |
+
- 自动代理检测(mihomo / clash / v2ray)
|
| 74 |
+
- 局域网登录分步教程
|
| 75 |
+
- Preact + Vite 前端架构
|
| 76 |
+
- Docker 容器部署支持
|
| 77 |
+
- 共享代理处理器,消除路由重复
|
| 78 |
+
|
| 79 |
+
### Changed
|
| 80 |
+
|
| 81 |
+
- Dashboard 重写为 Tailwind CSS
|
| 82 |
+
- 协议 / 语言两级标签页(OpenAI / Anthropic / Gemini × Python / cURL / Node.js)
|
| 83 |
+
- 内联 SVG 图标替换字体图标
|
| 84 |
+
- 系统字体替换 Google Fonts
|
| 85 |
+
- 架构审计修复(P0-P2 稳定性与可靠性)
|
| 86 |
+
|
| 87 |
+
### Fixed
|
| 88 |
+
|
| 89 |
+
- 移除所有 `any` 类型
|
| 90 |
+
- 修复图标文字闪烁(FOUC)
|
| 91 |
+
- 修复未认证时的重定向循环
|
| 92 |
+
- 移除虚假的 Claude / Gemini 模型别名,使用动态目录
|
| 93 |
+
- Dashboard 配置改为只读,修复 HTTP 复制按钮
|
| 94 |
+
- 恢复模型下拉选择器
|
| 95 |
+
|
| 96 |
+
## [v0.4.0](https://github.com/icebear0828/codex-proxy/releases/tag/v0.4.0) - 2026-02-19
|
| 97 |
+
|
| 98 |
+
### Added
|
| 99 |
+
|
| 100 |
+
- Anthropic Messages API 兼容路由(`POST /v1/messages`)
|
| 101 |
+
- Google Gemini API 兼容路由
|
| 102 |
+
- 桌面端上下文注入(模拟 Codex Desktop 请求特征)
|
| 103 |
+
- 多轮对话会话管理
|
| 104 |
+
- 自动更新检查管道(Appcast 轮询 + 版本提取)
|
| 105 |
+
- 中英双语 README
|
| 106 |
+
|
| 107 |
+
## [v0.3.0](https://github.com/icebear0828/codex-proxy/releases/tag/v0.3.0) - 2026-02-18
|
| 108 |
+
|
| 109 |
+
### Added
|
| 110 |
+
|
| 111 |
+
- curl-impersonate TLS 指纹模拟
|
| 112 |
+
- Chromium 版本自动检测与动态 `sec-ch-ua` 生成
|
| 113 |
+
- 请求时序 jitter 随机化
|
| 114 |
+
- Dashboard 实时代码示例与配额显示
|
| 115 |
+
|
| 116 |
+
### Fixed
|
| 117 |
+
|
| 118 |
+
- curl 请求修复
|
| 119 |
+
|
| 120 |
+
## [v0.2.0](https://github.com/icebear0828/codex-proxy/releases/tag/v0.2.0) - 2026-02-17
|
| 121 |
+
|
| 122 |
+
### Added
|
| 123 |
+
|
| 124 |
+
- Dashboard 多账户管理 UI
|
| 125 |
+
- OAuth PKCE 登录流程(固定 `localhost:1455` 回调)
|
| 126 |
+
- 架构审计:伪装加固、自动更新机制、健壮性提升
|
| 127 |
+
|
| 128 |
+
### Changed
|
| 129 |
+
|
| 130 |
+
- 硬编码值提取到配置文件
|
| 131 |
+
- 清理无用代码
|
| 132 |
+
|
| 133 |
+
## [v0.1.0](https://github.com/icebear0828/codex-proxy/releases/tag/v0.1.0) - 2026-02-17
|
| 134 |
+
|
| 135 |
+
### Added
|
| 136 |
+
|
| 137 |
+
- OpenAI `/v1/chat/completions` → Codex Responses API 反向代理核心
|
| 138 |
+
- 配额 API 查询(`/auth/accounts?quota=true`)
|
| 139 |
+
- Cloudflare TLS 指纹绕过
|
| 140 |
+
- SSE 流式响应转换
|
| 141 |
+
- 模型列表端点(`GET /v1/models`)
|
| 142 |
+
- 健康检查端点(`GET /health`)
|
Dockerfile
CHANGED
|
@@ -32,4 +32,12 @@ RUN npm prune --omit=dev && npm install --no-save tsx
|
|
| 32 |
|
| 33 |
VOLUME /app/data
|
| 34 |
EXPOSE 8080
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
CMD ["node", "dist/index.js"]
|
|
|
|
| 32 |
|
| 33 |
VOLUME /app/data
|
| 34 |
EXPOSE 8080
|
| 35 |
+
|
| 36 |
+
# Ensure writable directories for non-root user
|
| 37 |
+
RUN mkdir -p /app/data && chown -R node:node /app/data /app/config
|
| 38 |
+
|
| 39 |
+
USER node
|
| 40 |
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
| 41 |
+
CMD curl -fs http://localhost:8080/health || exit 1
|
| 42 |
+
|
| 43 |
CMD ["node", "dist/index.js"]
|
opencode.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "https://opencode.ai/config.json",
|
| 3 |
+
"provider": {
|
| 4 |
+
"codex-proxy": {
|
| 5 |
+
"npm": "@ai-sdk/openai-compatible",
|
| 6 |
+
"name": "Codex Proxy",
|
| 7 |
+
"options": {
|
| 8 |
+
"baseURL": "http://localhost:8080/v1",
|
| 9 |
+
"apiKey": "pwd"
|
| 10 |
+
},
|
| 11 |
+
"models": {
|
| 12 |
+
"codex": {
|
| 13 |
+
"name": "Codex (GPT-5.3)",
|
| 14 |
+
"attachment": true,
|
| 15 |
+
"limit": {
|
| 16 |
+
"context": 200000,
|
| 17 |
+
"output": 65536
|
| 18 |
+
}
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
}
|
| 23 |
+
}
|
package-lock.json
CHANGED
|
@@ -12,7 +12,6 @@
|
|
| 12 |
"@hono/node-server": "^1.0.0",
|
| 13 |
"hono": "^4.0.0",
|
| 14 |
"js-yaml": "^4.1.0",
|
| 15 |
-
"koffi": "^2.15.1",
|
| 16 |
"undici": "^7.0.0",
|
| 17 |
"zod": "^3.23.0"
|
| 18 |
},
|
|
@@ -22,7 +21,8 @@
|
|
| 22 |
"@types/node": "^22.0.0",
|
| 23 |
"js-beautify": "^1.15.0",
|
| 24 |
"tsx": "^4.0.0",
|
| 25 |
-
"typescript": "^5.5.0"
|
|
|
|
| 26 |
},
|
| 27 |
"optionalDependencies": {
|
| 28 |
"koffi": "^2.15.1"
|
|
@@ -518,39 +518,536 @@
|
|
| 518 |
"node": ">=12"
|
| 519 |
}
|
| 520 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
"node_modules/@one-ini/wasm": {
|
| 522 |
"version": "0.1.1",
|
| 523 |
"resolved": "https://registry.npmmirror.com/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
| 524 |
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
|
| 525 |
"dev": true,
|
| 526 |
-
"license": "MIT"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 527 |
},
|
| 528 |
-
"node_modules/@
|
| 529 |
-
"version": "
|
| 530 |
-
"resolved": "https://registry.npmmirror.com/@
|
| 531 |
-
"integrity": "sha512-
|
| 532 |
"dev": true,
|
| 533 |
"license": "MIT",
|
| 534 |
-
"
|
| 535 |
-
|
| 536 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 537 |
}
|
| 538 |
},
|
| 539 |
-
"node_modules/@
|
| 540 |
-
"version": "
|
| 541 |
-
"resolved": "https://registry.npmmirror.com/@
|
| 542 |
-
"integrity": "sha512-
|
| 543 |
"dev": true,
|
| 544 |
-
"license": "MIT"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 545 |
},
|
| 546 |
-
"node_modules/@
|
| 547 |
-
"version": "
|
| 548 |
-
"resolved": "https://registry.npmmirror.com/@
|
| 549 |
-
"integrity": "sha512-
|
| 550 |
"dev": true,
|
| 551 |
"license": "MIT",
|
| 552 |
"dependencies": {
|
| 553 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 554 |
}
|
| 555 |
},
|
| 556 |
"node_modules/abbrev": {
|
|
@@ -595,6 +1092,16 @@
|
|
| 595 |
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
| 596 |
"license": "Python-2.0"
|
| 597 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 598 |
"node_modules/balanced-match": {
|
| 599 |
"version": "1.0.2",
|
| 600 |
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
|
|
@@ -613,6 +1120,43 @@
|
|
| 613 |
"concat-map": "0.0.1"
|
| 614 |
}
|
| 615 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 616 |
"node_modules/color-convert": {
|
| 617 |
"version": "2.0.1",
|
| 618 |
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
|
|
@@ -676,6 +1220,34 @@
|
|
| 676 |
"node": ">= 8"
|
| 677 |
}
|
| 678 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 679 |
"node_modules/eastasianwidth": {
|
| 680 |
"version": "0.2.0",
|
| 681 |
"resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
|
@@ -745,6 +1317,13 @@
|
|
| 745 |
"dev": true,
|
| 746 |
"license": "MIT"
|
| 747 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 748 |
"node_modules/esbuild": {
|
| 749 |
"version": "0.27.3",
|
| 750 |
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.3.tgz",
|
|
@@ -787,6 +1366,44 @@
|
|
| 787 |
"@esbuild/win32-x64": "0.27.3"
|
| 788 |
}
|
| 789 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 790 |
"node_modules/foreground-child": {
|
| 791 |
"version": "3.3.1",
|
| 792 |
"resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz",
|
|
@@ -1008,6 +1625,13 @@
|
|
| 1008 |
"node": ">=14"
|
| 1009 |
}
|
| 1010 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1011 |
"node_modules/js-yaml": {
|
| 1012 |
"version": "4.1.1",
|
| 1013 |
"resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz",
|
|
@@ -1031,6 +1655,13 @@
|
|
| 1031 |
"url": "https://liberapay.com/Koromix"
|
| 1032 |
}
|
| 1033 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1034 |
"node_modules/lru-cache": {
|
| 1035 |
"version": "10.4.3",
|
| 1036 |
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz",
|
|
@@ -1038,6 +1669,16 @@
|
|
| 1038 |
"dev": true,
|
| 1039 |
"license": "ISC"
|
| 1040 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1041 |
"node_modules/minimatch": {
|
| 1042 |
"version": "3.1.2",
|
| 1043 |
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
|
|
@@ -1061,6 +1702,32 @@
|
|
| 1061 |
"node": ">=16 || 14 >=14.17"
|
| 1062 |
}
|
| 1063 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1064 |
"node_modules/nopt": {
|
| 1065 |
"version": "7.2.1",
|
| 1066 |
"resolved": "https://registry.npmmirror.com/nopt/-/nopt-7.2.1.tgz",
|
|
@@ -1131,6 +1798,72 @@
|
|
| 1131 |
"url": "https://github.com/sponsors/isaacs"
|
| 1132 |
}
|
| 1133 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1134 |
"node_modules/proto-list": {
|
| 1135 |
"version": "1.2.4",
|
| 1136 |
"resolved": "https://registry.npmmirror.com/proto-list/-/proto-list-1.2.4.tgz",
|
|
@@ -1148,6 +1881,51 @@
|
|
| 1148 |
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
| 1149 |
}
|
| 1150 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1151 |
"node_modules/semver": {
|
| 1152 |
"version": "7.7.4",
|
| 1153 |
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz",
|
|
@@ -1184,6 +1962,13 @@
|
|
| 1184 |
"node": ">=8"
|
| 1185 |
}
|
| 1186 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1187 |
"node_modules/signal-exit": {
|
| 1188 |
"version": "4.1.0",
|
| 1189 |
"resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz",
|
|
@@ -1197,6 +1982,30 @@
|
|
| 1197 |
"url": "https://github.com/sponsors/isaacs"
|
| 1198 |
}
|
| 1199 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1200 |
"node_modules/string-width": {
|
| 1201 |
"version": "5.1.2",
|
| 1202 |
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz",
|
|
@@ -1301,6 +2110,80 @@
|
|
| 1301 |
"node": ">=8"
|
| 1302 |
}
|
| 1303 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1304 |
"node_modules/tsx": {
|
| 1305 |
"version": "4.21.0",
|
| 1306 |
"resolved": "https://registry.npmmirror.com/tsx/-/tsx-4.21.0.tgz",
|
|
@@ -1351,6 +2234,177 @@
|
|
| 1351 |
"dev": true,
|
| 1352 |
"license": "MIT"
|
| 1353 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1354 |
"node_modules/which": {
|
| 1355 |
"version": "2.0.2",
|
| 1356 |
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
|
|
@@ -1367,6 +2421,23 @@
|
|
| 1367 |
"node": ">= 8"
|
| 1368 |
}
|
| 1369 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1370 |
"node_modules/wrap-ansi": {
|
| 1371 |
"version": "8.1.0",
|
| 1372 |
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
|
|
|
| 12 |
"@hono/node-server": "^1.0.0",
|
| 13 |
"hono": "^4.0.0",
|
| 14 |
"js-yaml": "^4.1.0",
|
|
|
|
| 15 |
"undici": "^7.0.0",
|
| 16 |
"zod": "^3.23.0"
|
| 17 |
},
|
|
|
|
| 21 |
"@types/node": "^22.0.0",
|
| 22 |
"js-beautify": "^1.15.0",
|
| 23 |
"tsx": "^4.0.0",
|
| 24 |
+
"typescript": "^5.5.0",
|
| 25 |
+
"vitest": "^3.2.4"
|
| 26 |
},
|
| 27 |
"optionalDependencies": {
|
| 28 |
"koffi": "^2.15.1"
|
|
|
|
| 518 |
"node": ">=12"
|
| 519 |
}
|
| 520 |
},
|
| 521 |
+
"node_modules/@jridgewell/sourcemap-codec": {
|
| 522 |
+
"version": "1.5.5",
|
| 523 |
+
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
| 524 |
+
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
| 525 |
+
"dev": true,
|
| 526 |
+
"license": "MIT"
|
| 527 |
+
},
|
| 528 |
"node_modules/@one-ini/wasm": {
|
| 529 |
"version": "0.1.1",
|
| 530 |
"resolved": "https://registry.npmmirror.com/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
| 531 |
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
|
| 532 |
"dev": true,
|
| 533 |
+
"license": "MIT"
|
| 534 |
+
},
|
| 535 |
+
"node_modules/@pkgjs/parseargs": {
|
| 536 |
+
"version": "0.11.0",
|
| 537 |
+
"resolved": "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
| 538 |
+
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
| 539 |
+
"dev": true,
|
| 540 |
+
"license": "MIT",
|
| 541 |
+
"optional": true,
|
| 542 |
+
"engines": {
|
| 543 |
+
"node": ">=14"
|
| 544 |
+
}
|
| 545 |
+
},
|
| 546 |
+
"node_modules/@rollup/rollup-android-arm-eabi": {
|
| 547 |
+
"version": "4.59.0",
|
| 548 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
|
| 549 |
+
"integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
|
| 550 |
+
"cpu": [
|
| 551 |
+
"arm"
|
| 552 |
+
],
|
| 553 |
+
"dev": true,
|
| 554 |
+
"license": "MIT",
|
| 555 |
+
"optional": true,
|
| 556 |
+
"os": [
|
| 557 |
+
"android"
|
| 558 |
+
]
|
| 559 |
+
},
|
| 560 |
+
"node_modules/@rollup/rollup-android-arm64": {
|
| 561 |
+
"version": "4.59.0",
|
| 562 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
|
| 563 |
+
"integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
|
| 564 |
+
"cpu": [
|
| 565 |
+
"arm64"
|
| 566 |
+
],
|
| 567 |
+
"dev": true,
|
| 568 |
+
"license": "MIT",
|
| 569 |
+
"optional": true,
|
| 570 |
+
"os": [
|
| 571 |
+
"android"
|
| 572 |
+
]
|
| 573 |
+
},
|
| 574 |
+
"node_modules/@rollup/rollup-darwin-arm64": {
|
| 575 |
+
"version": "4.59.0",
|
| 576 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
|
| 577 |
+
"integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
|
| 578 |
+
"cpu": [
|
| 579 |
+
"arm64"
|
| 580 |
+
],
|
| 581 |
+
"dev": true,
|
| 582 |
+
"license": "MIT",
|
| 583 |
+
"optional": true,
|
| 584 |
+
"os": [
|
| 585 |
+
"darwin"
|
| 586 |
+
]
|
| 587 |
+
},
|
| 588 |
+
"node_modules/@rollup/rollup-darwin-x64": {
|
| 589 |
+
"version": "4.59.0",
|
| 590 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
|
| 591 |
+
"integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
|
| 592 |
+
"cpu": [
|
| 593 |
+
"x64"
|
| 594 |
+
],
|
| 595 |
+
"dev": true,
|
| 596 |
+
"license": "MIT",
|
| 597 |
+
"optional": true,
|
| 598 |
+
"os": [
|
| 599 |
+
"darwin"
|
| 600 |
+
]
|
| 601 |
+
},
|
| 602 |
+
"node_modules/@rollup/rollup-freebsd-arm64": {
|
| 603 |
+
"version": "4.59.0",
|
| 604 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
|
| 605 |
+
"integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
|
| 606 |
+
"cpu": [
|
| 607 |
+
"arm64"
|
| 608 |
+
],
|
| 609 |
+
"dev": true,
|
| 610 |
+
"license": "MIT",
|
| 611 |
+
"optional": true,
|
| 612 |
+
"os": [
|
| 613 |
+
"freebsd"
|
| 614 |
+
]
|
| 615 |
+
},
|
| 616 |
+
"node_modules/@rollup/rollup-freebsd-x64": {
|
| 617 |
+
"version": "4.59.0",
|
| 618 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
|
| 619 |
+
"integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
|
| 620 |
+
"cpu": [
|
| 621 |
+
"x64"
|
| 622 |
+
],
|
| 623 |
+
"dev": true,
|
| 624 |
+
"license": "MIT",
|
| 625 |
+
"optional": true,
|
| 626 |
+
"os": [
|
| 627 |
+
"freebsd"
|
| 628 |
+
]
|
| 629 |
+
},
|
| 630 |
+
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
| 631 |
+
"version": "4.59.0",
|
| 632 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
|
| 633 |
+
"integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
|
| 634 |
+
"cpu": [
|
| 635 |
+
"arm"
|
| 636 |
+
],
|
| 637 |
+
"dev": true,
|
| 638 |
+
"license": "MIT",
|
| 639 |
+
"optional": true,
|
| 640 |
+
"os": [
|
| 641 |
+
"linux"
|
| 642 |
+
]
|
| 643 |
+
},
|
| 644 |
+
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
| 645 |
+
"version": "4.59.0",
|
| 646 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
|
| 647 |
+
"integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
|
| 648 |
+
"cpu": [
|
| 649 |
+
"arm"
|
| 650 |
+
],
|
| 651 |
+
"dev": true,
|
| 652 |
+
"license": "MIT",
|
| 653 |
+
"optional": true,
|
| 654 |
+
"os": [
|
| 655 |
+
"linux"
|
| 656 |
+
]
|
| 657 |
+
},
|
| 658 |
+
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
| 659 |
+
"version": "4.59.0",
|
| 660 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
|
| 661 |
+
"integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
|
| 662 |
+
"cpu": [
|
| 663 |
+
"arm64"
|
| 664 |
+
],
|
| 665 |
+
"dev": true,
|
| 666 |
+
"license": "MIT",
|
| 667 |
+
"optional": true,
|
| 668 |
+
"os": [
|
| 669 |
+
"linux"
|
| 670 |
+
]
|
| 671 |
+
},
|
| 672 |
+
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
| 673 |
+
"version": "4.59.0",
|
| 674 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
|
| 675 |
+
"integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
|
| 676 |
+
"cpu": [
|
| 677 |
+
"arm64"
|
| 678 |
+
],
|
| 679 |
+
"dev": true,
|
| 680 |
+
"license": "MIT",
|
| 681 |
+
"optional": true,
|
| 682 |
+
"os": [
|
| 683 |
+
"linux"
|
| 684 |
+
]
|
| 685 |
+
},
|
| 686 |
+
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
| 687 |
+
"version": "4.59.0",
|
| 688 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
|
| 689 |
+
"integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
|
| 690 |
+
"cpu": [
|
| 691 |
+
"loong64"
|
| 692 |
+
],
|
| 693 |
+
"dev": true,
|
| 694 |
+
"license": "MIT",
|
| 695 |
+
"optional": true,
|
| 696 |
+
"os": [
|
| 697 |
+
"linux"
|
| 698 |
+
]
|
| 699 |
+
},
|
| 700 |
+
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
| 701 |
+
"version": "4.59.0",
|
| 702 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
|
| 703 |
+
"integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
|
| 704 |
+
"cpu": [
|
| 705 |
+
"loong64"
|
| 706 |
+
],
|
| 707 |
+
"dev": true,
|
| 708 |
+
"license": "MIT",
|
| 709 |
+
"optional": true,
|
| 710 |
+
"os": [
|
| 711 |
+
"linux"
|
| 712 |
+
]
|
| 713 |
+
},
|
| 714 |
+
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
| 715 |
+
"version": "4.59.0",
|
| 716 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
|
| 717 |
+
"integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
|
| 718 |
+
"cpu": [
|
| 719 |
+
"ppc64"
|
| 720 |
+
],
|
| 721 |
+
"dev": true,
|
| 722 |
+
"license": "MIT",
|
| 723 |
+
"optional": true,
|
| 724 |
+
"os": [
|
| 725 |
+
"linux"
|
| 726 |
+
]
|
| 727 |
+
},
|
| 728 |
+
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
| 729 |
+
"version": "4.59.0",
|
| 730 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
|
| 731 |
+
"integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
|
| 732 |
+
"cpu": [
|
| 733 |
+
"ppc64"
|
| 734 |
+
],
|
| 735 |
+
"dev": true,
|
| 736 |
+
"license": "MIT",
|
| 737 |
+
"optional": true,
|
| 738 |
+
"os": [
|
| 739 |
+
"linux"
|
| 740 |
+
]
|
| 741 |
+
},
|
| 742 |
+
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
| 743 |
+
"version": "4.59.0",
|
| 744 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
|
| 745 |
+
"integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
|
| 746 |
+
"cpu": [
|
| 747 |
+
"riscv64"
|
| 748 |
+
],
|
| 749 |
+
"dev": true,
|
| 750 |
+
"license": "MIT",
|
| 751 |
+
"optional": true,
|
| 752 |
+
"os": [
|
| 753 |
+
"linux"
|
| 754 |
+
]
|
| 755 |
+
},
|
| 756 |
+
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
| 757 |
+
"version": "4.59.0",
|
| 758 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
|
| 759 |
+
"integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
|
| 760 |
+
"cpu": [
|
| 761 |
+
"riscv64"
|
| 762 |
+
],
|
| 763 |
+
"dev": true,
|
| 764 |
+
"license": "MIT",
|
| 765 |
+
"optional": true,
|
| 766 |
+
"os": [
|
| 767 |
+
"linux"
|
| 768 |
+
]
|
| 769 |
+
},
|
| 770 |
+
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
| 771 |
+
"version": "4.59.0",
|
| 772 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
|
| 773 |
+
"integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
|
| 774 |
+
"cpu": [
|
| 775 |
+
"s390x"
|
| 776 |
+
],
|
| 777 |
+
"dev": true,
|
| 778 |
+
"license": "MIT",
|
| 779 |
+
"optional": true,
|
| 780 |
+
"os": [
|
| 781 |
+
"linux"
|
| 782 |
+
]
|
| 783 |
+
},
|
| 784 |
+
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
| 785 |
+
"version": "4.59.0",
|
| 786 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
|
| 787 |
+
"integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
|
| 788 |
+
"cpu": [
|
| 789 |
+
"x64"
|
| 790 |
+
],
|
| 791 |
+
"dev": true,
|
| 792 |
+
"license": "MIT",
|
| 793 |
+
"optional": true,
|
| 794 |
+
"os": [
|
| 795 |
+
"linux"
|
| 796 |
+
]
|
| 797 |
+
},
|
| 798 |
+
"node_modules/@rollup/rollup-linux-x64-musl": {
|
| 799 |
+
"version": "4.59.0",
|
| 800 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
|
| 801 |
+
"integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
|
| 802 |
+
"cpu": [
|
| 803 |
+
"x64"
|
| 804 |
+
],
|
| 805 |
+
"dev": true,
|
| 806 |
+
"license": "MIT",
|
| 807 |
+
"optional": true,
|
| 808 |
+
"os": [
|
| 809 |
+
"linux"
|
| 810 |
+
]
|
| 811 |
+
},
|
| 812 |
+
"node_modules/@rollup/rollup-openbsd-x64": {
|
| 813 |
+
"version": "4.59.0",
|
| 814 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
|
| 815 |
+
"integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
|
| 816 |
+
"cpu": [
|
| 817 |
+
"x64"
|
| 818 |
+
],
|
| 819 |
+
"dev": true,
|
| 820 |
+
"license": "MIT",
|
| 821 |
+
"optional": true,
|
| 822 |
+
"os": [
|
| 823 |
+
"openbsd"
|
| 824 |
+
]
|
| 825 |
+
},
|
| 826 |
+
"node_modules/@rollup/rollup-openharmony-arm64": {
|
| 827 |
+
"version": "4.59.0",
|
| 828 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
|
| 829 |
+
"integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
|
| 830 |
+
"cpu": [
|
| 831 |
+
"arm64"
|
| 832 |
+
],
|
| 833 |
+
"dev": true,
|
| 834 |
+
"license": "MIT",
|
| 835 |
+
"optional": true,
|
| 836 |
+
"os": [
|
| 837 |
+
"openharmony"
|
| 838 |
+
]
|
| 839 |
+
},
|
| 840 |
+
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
| 841 |
+
"version": "4.59.0",
|
| 842 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
|
| 843 |
+
"integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
|
| 844 |
+
"cpu": [
|
| 845 |
+
"arm64"
|
| 846 |
+
],
|
| 847 |
+
"dev": true,
|
| 848 |
+
"license": "MIT",
|
| 849 |
+
"optional": true,
|
| 850 |
+
"os": [
|
| 851 |
+
"win32"
|
| 852 |
+
]
|
| 853 |
+
},
|
| 854 |
+
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
| 855 |
+
"version": "4.59.0",
|
| 856 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
|
| 857 |
+
"integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
|
| 858 |
+
"cpu": [
|
| 859 |
+
"ia32"
|
| 860 |
+
],
|
| 861 |
+
"dev": true,
|
| 862 |
+
"license": "MIT",
|
| 863 |
+
"optional": true,
|
| 864 |
+
"os": [
|
| 865 |
+
"win32"
|
| 866 |
+
]
|
| 867 |
+
},
|
| 868 |
+
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
| 869 |
+
"version": "4.59.0",
|
| 870 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
|
| 871 |
+
"integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
|
| 872 |
+
"cpu": [
|
| 873 |
+
"x64"
|
| 874 |
+
],
|
| 875 |
+
"dev": true,
|
| 876 |
+
"license": "MIT",
|
| 877 |
+
"optional": true,
|
| 878 |
+
"os": [
|
| 879 |
+
"win32"
|
| 880 |
+
]
|
| 881 |
+
},
|
| 882 |
+
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
| 883 |
+
"version": "4.59.0",
|
| 884 |
+
"resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
|
| 885 |
+
"integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
|
| 886 |
+
"cpu": [
|
| 887 |
+
"x64"
|
| 888 |
+
],
|
| 889 |
+
"dev": true,
|
| 890 |
+
"license": "MIT",
|
| 891 |
+
"optional": true,
|
| 892 |
+
"os": [
|
| 893 |
+
"win32"
|
| 894 |
+
]
|
| 895 |
+
},
|
| 896 |
+
"node_modules/@types/chai": {
|
| 897 |
+
"version": "5.2.3",
|
| 898 |
+
"resolved": "https://registry.npmmirror.com/@types/chai/-/chai-5.2.3.tgz",
|
| 899 |
+
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
|
| 900 |
+
"dev": true,
|
| 901 |
+
"license": "MIT",
|
| 902 |
+
"dependencies": {
|
| 903 |
+
"@types/deep-eql": "*",
|
| 904 |
+
"assertion-error": "^2.0.1"
|
| 905 |
+
}
|
| 906 |
+
},
|
| 907 |
+
"node_modules/@types/deep-eql": {
|
| 908 |
+
"version": "4.0.2",
|
| 909 |
+
"resolved": "https://registry.npmmirror.com/@types/deep-eql/-/deep-eql-4.0.2.tgz",
|
| 910 |
+
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
|
| 911 |
+
"dev": true,
|
| 912 |
+
"license": "MIT"
|
| 913 |
+
},
|
| 914 |
+
"node_modules/@types/estree": {
|
| 915 |
+
"version": "1.0.8",
|
| 916 |
+
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz",
|
| 917 |
+
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
| 918 |
+
"dev": true,
|
| 919 |
+
"license": "MIT"
|
| 920 |
+
},
|
| 921 |
+
"node_modules/@types/js-yaml": {
|
| 922 |
+
"version": "4.0.9",
|
| 923 |
+
"resolved": "https://registry.npmmirror.com/@types/js-yaml/-/js-yaml-4.0.9.tgz",
|
| 924 |
+
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
|
| 925 |
+
"dev": true,
|
| 926 |
+
"license": "MIT"
|
| 927 |
+
},
|
| 928 |
+
"node_modules/@types/node": {
|
| 929 |
+
"version": "22.19.11",
|
| 930 |
+
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.19.11.tgz",
|
| 931 |
+
"integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==",
|
| 932 |
+
"dev": true,
|
| 933 |
+
"license": "MIT",
|
| 934 |
+
"dependencies": {
|
| 935 |
+
"undici-types": "~6.21.0"
|
| 936 |
+
}
|
| 937 |
+
},
|
| 938 |
+
"node_modules/@vitest/expect": {
|
| 939 |
+
"version": "3.2.4",
|
| 940 |
+
"resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-3.2.4.tgz",
|
| 941 |
+
"integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
|
| 942 |
+
"dev": true,
|
| 943 |
+
"license": "MIT",
|
| 944 |
+
"dependencies": {
|
| 945 |
+
"@types/chai": "^5.2.2",
|
| 946 |
+
"@vitest/spy": "3.2.4",
|
| 947 |
+
"@vitest/utils": "3.2.4",
|
| 948 |
+
"chai": "^5.2.0",
|
| 949 |
+
"tinyrainbow": "^2.0.0"
|
| 950 |
+
},
|
| 951 |
+
"funding": {
|
| 952 |
+
"url": "https://opencollective.com/vitest"
|
| 953 |
+
}
|
| 954 |
+
},
|
| 955 |
+
"node_modules/@vitest/mocker": {
|
| 956 |
+
"version": "3.2.4",
|
| 957 |
+
"resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-3.2.4.tgz",
|
| 958 |
+
"integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
|
| 959 |
+
"dev": true,
|
| 960 |
+
"license": "MIT",
|
| 961 |
+
"dependencies": {
|
| 962 |
+
"@vitest/spy": "3.2.4",
|
| 963 |
+
"estree-walker": "^3.0.3",
|
| 964 |
+
"magic-string": "^0.30.17"
|
| 965 |
+
},
|
| 966 |
+
"funding": {
|
| 967 |
+
"url": "https://opencollective.com/vitest"
|
| 968 |
+
},
|
| 969 |
+
"peerDependencies": {
|
| 970 |
+
"msw": "^2.4.9",
|
| 971 |
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
|
| 972 |
+
},
|
| 973 |
+
"peerDependenciesMeta": {
|
| 974 |
+
"msw": {
|
| 975 |
+
"optional": true
|
| 976 |
+
},
|
| 977 |
+
"vite": {
|
| 978 |
+
"optional": true
|
| 979 |
+
}
|
| 980 |
+
}
|
| 981 |
+
},
|
| 982 |
+
"node_modules/@vitest/pretty-format": {
|
| 983 |
+
"version": "3.2.4",
|
| 984 |
+
"resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
|
| 985 |
+
"integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
|
| 986 |
+
"dev": true,
|
| 987 |
+
"license": "MIT",
|
| 988 |
+
"dependencies": {
|
| 989 |
+
"tinyrainbow": "^2.0.0"
|
| 990 |
+
},
|
| 991 |
+
"funding": {
|
| 992 |
+
"url": "https://opencollective.com/vitest"
|
| 993 |
+
}
|
| 994 |
+
},
|
| 995 |
+
"node_modules/@vitest/runner": {
|
| 996 |
+
"version": "3.2.4",
|
| 997 |
+
"resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-3.2.4.tgz",
|
| 998 |
+
"integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
|
| 999 |
+
"dev": true,
|
| 1000 |
+
"license": "MIT",
|
| 1001 |
+
"dependencies": {
|
| 1002 |
+
"@vitest/utils": "3.2.4",
|
| 1003 |
+
"pathe": "^2.0.3",
|
| 1004 |
+
"strip-literal": "^3.0.0"
|
| 1005 |
+
},
|
| 1006 |
+
"funding": {
|
| 1007 |
+
"url": "https://opencollective.com/vitest"
|
| 1008 |
+
}
|
| 1009 |
},
|
| 1010 |
+
"node_modules/@vitest/snapshot": {
|
| 1011 |
+
"version": "3.2.4",
|
| 1012 |
+
"resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-3.2.4.tgz",
|
| 1013 |
+
"integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
|
| 1014 |
"dev": true,
|
| 1015 |
"license": "MIT",
|
| 1016 |
+
"dependencies": {
|
| 1017 |
+
"@vitest/pretty-format": "3.2.4",
|
| 1018 |
+
"magic-string": "^0.30.17",
|
| 1019 |
+
"pathe": "^2.0.3"
|
| 1020 |
+
},
|
| 1021 |
+
"funding": {
|
| 1022 |
+
"url": "https://opencollective.com/vitest"
|
| 1023 |
}
|
| 1024 |
},
|
| 1025 |
+
"node_modules/@vitest/spy": {
|
| 1026 |
+
"version": "3.2.4",
|
| 1027 |
+
"resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-3.2.4.tgz",
|
| 1028 |
+
"integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
|
| 1029 |
"dev": true,
|
| 1030 |
+
"license": "MIT",
|
| 1031 |
+
"dependencies": {
|
| 1032 |
+
"tinyspy": "^4.0.3"
|
| 1033 |
+
},
|
| 1034 |
+
"funding": {
|
| 1035 |
+
"url": "https://opencollective.com/vitest"
|
| 1036 |
+
}
|
| 1037 |
},
|
| 1038 |
+
"node_modules/@vitest/utils": {
|
| 1039 |
+
"version": "3.2.4",
|
| 1040 |
+
"resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-3.2.4.tgz",
|
| 1041 |
+
"integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
|
| 1042 |
"dev": true,
|
| 1043 |
"license": "MIT",
|
| 1044 |
"dependencies": {
|
| 1045 |
+
"@vitest/pretty-format": "3.2.4",
|
| 1046 |
+
"loupe": "^3.1.4",
|
| 1047 |
+
"tinyrainbow": "^2.0.0"
|
| 1048 |
+
},
|
| 1049 |
+
"funding": {
|
| 1050 |
+
"url": "https://opencollective.com/vitest"
|
| 1051 |
}
|
| 1052 |
},
|
| 1053 |
"node_modules/abbrev": {
|
|
|
|
| 1092 |
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
| 1093 |
"license": "Python-2.0"
|
| 1094 |
},
|
| 1095 |
+
"node_modules/assertion-error": {
|
| 1096 |
+
"version": "2.0.1",
|
| 1097 |
+
"resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz",
|
| 1098 |
+
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
|
| 1099 |
+
"dev": true,
|
| 1100 |
+
"license": "MIT",
|
| 1101 |
+
"engines": {
|
| 1102 |
+
"node": ">=12"
|
| 1103 |
+
}
|
| 1104 |
+
},
|
| 1105 |
"node_modules/balanced-match": {
|
| 1106 |
"version": "1.0.2",
|
| 1107 |
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
|
|
|
|
| 1120 |
"concat-map": "0.0.1"
|
| 1121 |
}
|
| 1122 |
},
|
| 1123 |
+
"node_modules/cac": {
|
| 1124 |
+
"version": "6.7.14",
|
| 1125 |
+
"resolved": "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz",
|
| 1126 |
+
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
|
| 1127 |
+
"dev": true,
|
| 1128 |
+
"license": "MIT",
|
| 1129 |
+
"engines": {
|
| 1130 |
+
"node": ">=8"
|
| 1131 |
+
}
|
| 1132 |
+
},
|
| 1133 |
+
"node_modules/chai": {
|
| 1134 |
+
"version": "5.3.3",
|
| 1135 |
+
"resolved": "https://registry.npmmirror.com/chai/-/chai-5.3.3.tgz",
|
| 1136 |
+
"integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
|
| 1137 |
+
"dev": true,
|
| 1138 |
+
"license": "MIT",
|
| 1139 |
+
"dependencies": {
|
| 1140 |
+
"assertion-error": "^2.0.1",
|
| 1141 |
+
"check-error": "^2.1.1",
|
| 1142 |
+
"deep-eql": "^5.0.1",
|
| 1143 |
+
"loupe": "^3.1.0",
|
| 1144 |
+
"pathval": "^2.0.0"
|
| 1145 |
+
},
|
| 1146 |
+
"engines": {
|
| 1147 |
+
"node": ">=18"
|
| 1148 |
+
}
|
| 1149 |
+
},
|
| 1150 |
+
"node_modules/check-error": {
|
| 1151 |
+
"version": "2.1.3",
|
| 1152 |
+
"resolved": "https://registry.npmmirror.com/check-error/-/check-error-2.1.3.tgz",
|
| 1153 |
+
"integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
|
| 1154 |
+
"dev": true,
|
| 1155 |
+
"license": "MIT",
|
| 1156 |
+
"engines": {
|
| 1157 |
+
"node": ">= 16"
|
| 1158 |
+
}
|
| 1159 |
+
},
|
| 1160 |
"node_modules/color-convert": {
|
| 1161 |
"version": "2.0.1",
|
| 1162 |
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
|
|
|
|
| 1220 |
"node": ">= 8"
|
| 1221 |
}
|
| 1222 |
},
|
| 1223 |
+
"node_modules/debug": {
|
| 1224 |
+
"version": "4.4.3",
|
| 1225 |
+
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz",
|
| 1226 |
+
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
| 1227 |
+
"dev": true,
|
| 1228 |
+
"license": "MIT",
|
| 1229 |
+
"dependencies": {
|
| 1230 |
+
"ms": "^2.1.3"
|
| 1231 |
+
},
|
| 1232 |
+
"engines": {
|
| 1233 |
+
"node": ">=6.0"
|
| 1234 |
+
},
|
| 1235 |
+
"peerDependenciesMeta": {
|
| 1236 |
+
"supports-color": {
|
| 1237 |
+
"optional": true
|
| 1238 |
+
}
|
| 1239 |
+
}
|
| 1240 |
+
},
|
| 1241 |
+
"node_modules/deep-eql": {
|
| 1242 |
+
"version": "5.0.2",
|
| 1243 |
+
"resolved": "https://registry.npmmirror.com/deep-eql/-/deep-eql-5.0.2.tgz",
|
| 1244 |
+
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
|
| 1245 |
+
"dev": true,
|
| 1246 |
+
"license": "MIT",
|
| 1247 |
+
"engines": {
|
| 1248 |
+
"node": ">=6"
|
| 1249 |
+
}
|
| 1250 |
+
},
|
| 1251 |
"node_modules/eastasianwidth": {
|
| 1252 |
"version": "0.2.0",
|
| 1253 |
"resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
|
|
|
| 1317 |
"dev": true,
|
| 1318 |
"license": "MIT"
|
| 1319 |
},
|
| 1320 |
+
"node_modules/es-module-lexer": {
|
| 1321 |
+
"version": "1.7.0",
|
| 1322 |
+
"resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
| 1323 |
+
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
| 1324 |
+
"dev": true,
|
| 1325 |
+
"license": "MIT"
|
| 1326 |
+
},
|
| 1327 |
"node_modules/esbuild": {
|
| 1328 |
"version": "0.27.3",
|
| 1329 |
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.3.tgz",
|
|
|
|
| 1366 |
"@esbuild/win32-x64": "0.27.3"
|
| 1367 |
}
|
| 1368 |
},
|
| 1369 |
+
"node_modules/estree-walker": {
|
| 1370 |
+
"version": "3.0.3",
|
| 1371 |
+
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz",
|
| 1372 |
+
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
| 1373 |
+
"dev": true,
|
| 1374 |
+
"license": "MIT",
|
| 1375 |
+
"dependencies": {
|
| 1376 |
+
"@types/estree": "^1.0.0"
|
| 1377 |
+
}
|
| 1378 |
+
},
|
| 1379 |
+
"node_modules/expect-type": {
|
| 1380 |
+
"version": "1.3.0",
|
| 1381 |
+
"resolved": "https://registry.npmmirror.com/expect-type/-/expect-type-1.3.0.tgz",
|
| 1382 |
+
"integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
|
| 1383 |
+
"dev": true,
|
| 1384 |
+
"license": "Apache-2.0",
|
| 1385 |
+
"engines": {
|
| 1386 |
+
"node": ">=12.0.0"
|
| 1387 |
+
}
|
| 1388 |
+
},
|
| 1389 |
+
"node_modules/fdir": {
|
| 1390 |
+
"version": "6.5.0",
|
| 1391 |
+
"resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz",
|
| 1392 |
+
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
| 1393 |
+
"dev": true,
|
| 1394 |
+
"license": "MIT",
|
| 1395 |
+
"engines": {
|
| 1396 |
+
"node": ">=12.0.0"
|
| 1397 |
+
},
|
| 1398 |
+
"peerDependencies": {
|
| 1399 |
+
"picomatch": "^3 || ^4"
|
| 1400 |
+
},
|
| 1401 |
+
"peerDependenciesMeta": {
|
| 1402 |
+
"picomatch": {
|
| 1403 |
+
"optional": true
|
| 1404 |
+
}
|
| 1405 |
+
}
|
| 1406 |
+
},
|
| 1407 |
"node_modules/foreground-child": {
|
| 1408 |
"version": "3.3.1",
|
| 1409 |
"resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz",
|
|
|
|
| 1625 |
"node": ">=14"
|
| 1626 |
}
|
| 1627 |
},
|
| 1628 |
+
"node_modules/js-tokens": {
|
| 1629 |
+
"version": "9.0.1",
|
| 1630 |
+
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-9.0.1.tgz",
|
| 1631 |
+
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
|
| 1632 |
+
"dev": true,
|
| 1633 |
+
"license": "MIT"
|
| 1634 |
+
},
|
| 1635 |
"node_modules/js-yaml": {
|
| 1636 |
"version": "4.1.1",
|
| 1637 |
"resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz",
|
|
|
|
| 1655 |
"url": "https://liberapay.com/Koromix"
|
| 1656 |
}
|
| 1657 |
},
|
| 1658 |
+
"node_modules/loupe": {
|
| 1659 |
+
"version": "3.2.1",
|
| 1660 |
+
"resolved": "https://registry.npmmirror.com/loupe/-/loupe-3.2.1.tgz",
|
| 1661 |
+
"integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
|
| 1662 |
+
"dev": true,
|
| 1663 |
+
"license": "MIT"
|
| 1664 |
+
},
|
| 1665 |
"node_modules/lru-cache": {
|
| 1666 |
"version": "10.4.3",
|
| 1667 |
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz",
|
|
|
|
| 1669 |
"dev": true,
|
| 1670 |
"license": "ISC"
|
| 1671 |
},
|
| 1672 |
+
"node_modules/magic-string": {
|
| 1673 |
+
"version": "0.30.21",
|
| 1674 |
+
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz",
|
| 1675 |
+
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
| 1676 |
+
"dev": true,
|
| 1677 |
+
"license": "MIT",
|
| 1678 |
+
"dependencies": {
|
| 1679 |
+
"@jridgewell/sourcemap-codec": "^1.5.5"
|
| 1680 |
+
}
|
| 1681 |
+
},
|
| 1682 |
"node_modules/minimatch": {
|
| 1683 |
"version": "3.1.2",
|
| 1684 |
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
|
|
|
|
| 1702 |
"node": ">=16 || 14 >=14.17"
|
| 1703 |
}
|
| 1704 |
},
|
| 1705 |
+
"node_modules/ms": {
|
| 1706 |
+
"version": "2.1.3",
|
| 1707 |
+
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
| 1708 |
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
| 1709 |
+
"dev": true,
|
| 1710 |
+
"license": "MIT"
|
| 1711 |
+
},
|
| 1712 |
+
"node_modules/nanoid": {
|
| 1713 |
+
"version": "3.3.11",
|
| 1714 |
+
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz",
|
| 1715 |
+
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
| 1716 |
+
"dev": true,
|
| 1717 |
+
"funding": [
|
| 1718 |
+
{
|
| 1719 |
+
"type": "github",
|
| 1720 |
+
"url": "https://github.com/sponsors/ai"
|
| 1721 |
+
}
|
| 1722 |
+
],
|
| 1723 |
+
"license": "MIT",
|
| 1724 |
+
"bin": {
|
| 1725 |
+
"nanoid": "bin/nanoid.cjs"
|
| 1726 |
+
},
|
| 1727 |
+
"engines": {
|
| 1728 |
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
| 1729 |
+
}
|
| 1730 |
+
},
|
| 1731 |
"node_modules/nopt": {
|
| 1732 |
"version": "7.2.1",
|
| 1733 |
"resolved": "https://registry.npmmirror.com/nopt/-/nopt-7.2.1.tgz",
|
|
|
|
| 1798 |
"url": "https://github.com/sponsors/isaacs"
|
| 1799 |
}
|
| 1800 |
},
|
| 1801 |
+
"node_modules/pathe": {
|
| 1802 |
+
"version": "2.0.3",
|
| 1803 |
+
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
|
| 1804 |
+
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
| 1805 |
+
"dev": true,
|
| 1806 |
+
"license": "MIT"
|
| 1807 |
+
},
|
| 1808 |
+
"node_modules/pathval": {
|
| 1809 |
+
"version": "2.0.1",
|
| 1810 |
+
"resolved": "https://registry.npmmirror.com/pathval/-/pathval-2.0.1.tgz",
|
| 1811 |
+
"integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
|
| 1812 |
+
"dev": true,
|
| 1813 |
+
"license": "MIT",
|
| 1814 |
+
"engines": {
|
| 1815 |
+
"node": ">= 14.16"
|
| 1816 |
+
}
|
| 1817 |
+
},
|
| 1818 |
+
"node_modules/picocolors": {
|
| 1819 |
+
"version": "1.1.1",
|
| 1820 |
+
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
|
| 1821 |
+
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
| 1822 |
+
"dev": true,
|
| 1823 |
+
"license": "ISC"
|
| 1824 |
+
},
|
| 1825 |
+
"node_modules/picomatch": {
|
| 1826 |
+
"version": "4.0.3",
|
| 1827 |
+
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
|
| 1828 |
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
| 1829 |
+
"dev": true,
|
| 1830 |
+
"license": "MIT",
|
| 1831 |
+
"engines": {
|
| 1832 |
+
"node": ">=12"
|
| 1833 |
+
},
|
| 1834 |
+
"funding": {
|
| 1835 |
+
"url": "https://github.com/sponsors/jonschlinkert"
|
| 1836 |
+
}
|
| 1837 |
+
},
|
| 1838 |
+
"node_modules/postcss": {
|
| 1839 |
+
"version": "8.5.6",
|
| 1840 |
+
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz",
|
| 1841 |
+
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
| 1842 |
+
"dev": true,
|
| 1843 |
+
"funding": [
|
| 1844 |
+
{
|
| 1845 |
+
"type": "opencollective",
|
| 1846 |
+
"url": "https://opencollective.com/postcss/"
|
| 1847 |
+
},
|
| 1848 |
+
{
|
| 1849 |
+
"type": "tidelift",
|
| 1850 |
+
"url": "https://tidelift.com/funding/github/npm/postcss"
|
| 1851 |
+
},
|
| 1852 |
+
{
|
| 1853 |
+
"type": "github",
|
| 1854 |
+
"url": "https://github.com/sponsors/ai"
|
| 1855 |
+
}
|
| 1856 |
+
],
|
| 1857 |
+
"license": "MIT",
|
| 1858 |
+
"dependencies": {
|
| 1859 |
+
"nanoid": "^3.3.11",
|
| 1860 |
+
"picocolors": "^1.1.1",
|
| 1861 |
+
"source-map-js": "^1.2.1"
|
| 1862 |
+
},
|
| 1863 |
+
"engines": {
|
| 1864 |
+
"node": "^10 || ^12 || >=14"
|
| 1865 |
+
}
|
| 1866 |
+
},
|
| 1867 |
"node_modules/proto-list": {
|
| 1868 |
"version": "1.2.4",
|
| 1869 |
"resolved": "https://registry.npmmirror.com/proto-list/-/proto-list-1.2.4.tgz",
|
|
|
|
| 1881 |
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
| 1882 |
}
|
| 1883 |
},
|
| 1884 |
+
"node_modules/rollup": {
|
| 1885 |
+
"version": "4.59.0",
|
| 1886 |
+
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.59.0.tgz",
|
| 1887 |
+
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
|
| 1888 |
+
"dev": true,
|
| 1889 |
+
"license": "MIT",
|
| 1890 |
+
"dependencies": {
|
| 1891 |
+
"@types/estree": "1.0.8"
|
| 1892 |
+
},
|
| 1893 |
+
"bin": {
|
| 1894 |
+
"rollup": "dist/bin/rollup"
|
| 1895 |
+
},
|
| 1896 |
+
"engines": {
|
| 1897 |
+
"node": ">=18.0.0",
|
| 1898 |
+
"npm": ">=8.0.0"
|
| 1899 |
+
},
|
| 1900 |
+
"optionalDependencies": {
|
| 1901 |
+
"@rollup/rollup-android-arm-eabi": "4.59.0",
|
| 1902 |
+
"@rollup/rollup-android-arm64": "4.59.0",
|
| 1903 |
+
"@rollup/rollup-darwin-arm64": "4.59.0",
|
| 1904 |
+
"@rollup/rollup-darwin-x64": "4.59.0",
|
| 1905 |
+
"@rollup/rollup-freebsd-arm64": "4.59.0",
|
| 1906 |
+
"@rollup/rollup-freebsd-x64": "4.59.0",
|
| 1907 |
+
"@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
|
| 1908 |
+
"@rollup/rollup-linux-arm-musleabihf": "4.59.0",
|
| 1909 |
+
"@rollup/rollup-linux-arm64-gnu": "4.59.0",
|
| 1910 |
+
"@rollup/rollup-linux-arm64-musl": "4.59.0",
|
| 1911 |
+
"@rollup/rollup-linux-loong64-gnu": "4.59.0",
|
| 1912 |
+
"@rollup/rollup-linux-loong64-musl": "4.59.0",
|
| 1913 |
+
"@rollup/rollup-linux-ppc64-gnu": "4.59.0",
|
| 1914 |
+
"@rollup/rollup-linux-ppc64-musl": "4.59.0",
|
| 1915 |
+
"@rollup/rollup-linux-riscv64-gnu": "4.59.0",
|
| 1916 |
+
"@rollup/rollup-linux-riscv64-musl": "4.59.0",
|
| 1917 |
+
"@rollup/rollup-linux-s390x-gnu": "4.59.0",
|
| 1918 |
+
"@rollup/rollup-linux-x64-gnu": "4.59.0",
|
| 1919 |
+
"@rollup/rollup-linux-x64-musl": "4.59.0",
|
| 1920 |
+
"@rollup/rollup-openbsd-x64": "4.59.0",
|
| 1921 |
+
"@rollup/rollup-openharmony-arm64": "4.59.0",
|
| 1922 |
+
"@rollup/rollup-win32-arm64-msvc": "4.59.0",
|
| 1923 |
+
"@rollup/rollup-win32-ia32-msvc": "4.59.0",
|
| 1924 |
+
"@rollup/rollup-win32-x64-gnu": "4.59.0",
|
| 1925 |
+
"@rollup/rollup-win32-x64-msvc": "4.59.0",
|
| 1926 |
+
"fsevents": "~2.3.2"
|
| 1927 |
+
}
|
| 1928 |
+
},
|
| 1929 |
"node_modules/semver": {
|
| 1930 |
"version": "7.7.4",
|
| 1931 |
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz",
|
|
|
|
| 1962 |
"node": ">=8"
|
| 1963 |
}
|
| 1964 |
},
|
| 1965 |
+
"node_modules/siginfo": {
|
| 1966 |
+
"version": "2.0.0",
|
| 1967 |
+
"resolved": "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz",
|
| 1968 |
+
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
|
| 1969 |
+
"dev": true,
|
| 1970 |
+
"license": "ISC"
|
| 1971 |
+
},
|
| 1972 |
"node_modules/signal-exit": {
|
| 1973 |
"version": "4.1.0",
|
| 1974 |
"resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz",
|
|
|
|
| 1982 |
"url": "https://github.com/sponsors/isaacs"
|
| 1983 |
}
|
| 1984 |
},
|
| 1985 |
+
"node_modules/source-map-js": {
|
| 1986 |
+
"version": "1.2.1",
|
| 1987 |
+
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
|
| 1988 |
+
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
| 1989 |
+
"dev": true,
|
| 1990 |
+
"license": "BSD-3-Clause",
|
| 1991 |
+
"engines": {
|
| 1992 |
+
"node": ">=0.10.0"
|
| 1993 |
+
}
|
| 1994 |
+
},
|
| 1995 |
+
"node_modules/stackback": {
|
| 1996 |
+
"version": "0.0.2",
|
| 1997 |
+
"resolved": "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz",
|
| 1998 |
+
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
|
| 1999 |
+
"dev": true,
|
| 2000 |
+
"license": "MIT"
|
| 2001 |
+
},
|
| 2002 |
+
"node_modules/std-env": {
|
| 2003 |
+
"version": "3.10.0",
|
| 2004 |
+
"resolved": "https://registry.npmmirror.com/std-env/-/std-env-3.10.0.tgz",
|
| 2005 |
+
"integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
|
| 2006 |
+
"dev": true,
|
| 2007 |
+
"license": "MIT"
|
| 2008 |
+
},
|
| 2009 |
"node_modules/string-width": {
|
| 2010 |
"version": "5.1.2",
|
| 2011 |
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz",
|
|
|
|
| 2110 |
"node": ">=8"
|
| 2111 |
}
|
| 2112 |
},
|
| 2113 |
+
"node_modules/strip-literal": {
|
| 2114 |
+
"version": "3.1.0",
|
| 2115 |
+
"resolved": "https://registry.npmmirror.com/strip-literal/-/strip-literal-3.1.0.tgz",
|
| 2116 |
+
"integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
|
| 2117 |
+
"dev": true,
|
| 2118 |
+
"license": "MIT",
|
| 2119 |
+
"dependencies": {
|
| 2120 |
+
"js-tokens": "^9.0.1"
|
| 2121 |
+
},
|
| 2122 |
+
"funding": {
|
| 2123 |
+
"url": "https://github.com/sponsors/antfu"
|
| 2124 |
+
}
|
| 2125 |
+
},
|
| 2126 |
+
"node_modules/tinybench": {
|
| 2127 |
+
"version": "2.9.0",
|
| 2128 |
+
"resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.9.0.tgz",
|
| 2129 |
+
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
|
| 2130 |
+
"dev": true,
|
| 2131 |
+
"license": "MIT"
|
| 2132 |
+
},
|
| 2133 |
+
"node_modules/tinyexec": {
|
| 2134 |
+
"version": "0.3.2",
|
| 2135 |
+
"resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-0.3.2.tgz",
|
| 2136 |
+
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
|
| 2137 |
+
"dev": true,
|
| 2138 |
+
"license": "MIT"
|
| 2139 |
+
},
|
| 2140 |
+
"node_modules/tinyglobby": {
|
| 2141 |
+
"version": "0.2.15",
|
| 2142 |
+
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
| 2143 |
+
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
| 2144 |
+
"dev": true,
|
| 2145 |
+
"license": "MIT",
|
| 2146 |
+
"dependencies": {
|
| 2147 |
+
"fdir": "^6.5.0",
|
| 2148 |
+
"picomatch": "^4.0.3"
|
| 2149 |
+
},
|
| 2150 |
+
"engines": {
|
| 2151 |
+
"node": ">=12.0.0"
|
| 2152 |
+
},
|
| 2153 |
+
"funding": {
|
| 2154 |
+
"url": "https://github.com/sponsors/SuperchupuDev"
|
| 2155 |
+
}
|
| 2156 |
+
},
|
| 2157 |
+
"node_modules/tinypool": {
|
| 2158 |
+
"version": "1.1.1",
|
| 2159 |
+
"resolved": "https://registry.npmmirror.com/tinypool/-/tinypool-1.1.1.tgz",
|
| 2160 |
+
"integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
|
| 2161 |
+
"dev": true,
|
| 2162 |
+
"license": "MIT",
|
| 2163 |
+
"engines": {
|
| 2164 |
+
"node": "^18.0.0 || >=20.0.0"
|
| 2165 |
+
}
|
| 2166 |
+
},
|
| 2167 |
+
"node_modules/tinyrainbow": {
|
| 2168 |
+
"version": "2.0.0",
|
| 2169 |
+
"resolved": "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
|
| 2170 |
+
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
|
| 2171 |
+
"dev": true,
|
| 2172 |
+
"license": "MIT",
|
| 2173 |
+
"engines": {
|
| 2174 |
+
"node": ">=14.0.0"
|
| 2175 |
+
}
|
| 2176 |
+
},
|
| 2177 |
+
"node_modules/tinyspy": {
|
| 2178 |
+
"version": "4.0.4",
|
| 2179 |
+
"resolved": "https://registry.npmmirror.com/tinyspy/-/tinyspy-4.0.4.tgz",
|
| 2180 |
+
"integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
|
| 2181 |
+
"dev": true,
|
| 2182 |
+
"license": "MIT",
|
| 2183 |
+
"engines": {
|
| 2184 |
+
"node": ">=14.0.0"
|
| 2185 |
+
}
|
| 2186 |
+
},
|
| 2187 |
"node_modules/tsx": {
|
| 2188 |
"version": "4.21.0",
|
| 2189 |
"resolved": "https://registry.npmmirror.com/tsx/-/tsx-4.21.0.tgz",
|
|
|
|
| 2234 |
"dev": true,
|
| 2235 |
"license": "MIT"
|
| 2236 |
},
|
| 2237 |
+
"node_modules/vite": {
|
| 2238 |
+
"version": "7.3.1",
|
| 2239 |
+
"resolved": "https://registry.npmmirror.com/vite/-/vite-7.3.1.tgz",
|
| 2240 |
+
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
| 2241 |
+
"dev": true,
|
| 2242 |
+
"license": "MIT",
|
| 2243 |
+
"dependencies": {
|
| 2244 |
+
"esbuild": "^0.27.0",
|
| 2245 |
+
"fdir": "^6.5.0",
|
| 2246 |
+
"picomatch": "^4.0.3",
|
| 2247 |
+
"postcss": "^8.5.6",
|
| 2248 |
+
"rollup": "^4.43.0",
|
| 2249 |
+
"tinyglobby": "^0.2.15"
|
| 2250 |
+
},
|
| 2251 |
+
"bin": {
|
| 2252 |
+
"vite": "bin/vite.js"
|
| 2253 |
+
},
|
| 2254 |
+
"engines": {
|
| 2255 |
+
"node": "^20.19.0 || >=22.12.0"
|
| 2256 |
+
},
|
| 2257 |
+
"funding": {
|
| 2258 |
+
"url": "https://github.com/vitejs/vite?sponsor=1"
|
| 2259 |
+
},
|
| 2260 |
+
"optionalDependencies": {
|
| 2261 |
+
"fsevents": "~2.3.3"
|
| 2262 |
+
},
|
| 2263 |
+
"peerDependencies": {
|
| 2264 |
+
"@types/node": "^20.19.0 || >=22.12.0",
|
| 2265 |
+
"jiti": ">=1.21.0",
|
| 2266 |
+
"less": "^4.0.0",
|
| 2267 |
+
"lightningcss": "^1.21.0",
|
| 2268 |
+
"sass": "^1.70.0",
|
| 2269 |
+
"sass-embedded": "^1.70.0",
|
| 2270 |
+
"stylus": ">=0.54.8",
|
| 2271 |
+
"sugarss": "^5.0.0",
|
| 2272 |
+
"terser": "^5.16.0",
|
| 2273 |
+
"tsx": "^4.8.1",
|
| 2274 |
+
"yaml": "^2.4.2"
|
| 2275 |
+
},
|
| 2276 |
+
"peerDependenciesMeta": {
|
| 2277 |
+
"@types/node": {
|
| 2278 |
+
"optional": true
|
| 2279 |
+
},
|
| 2280 |
+
"jiti": {
|
| 2281 |
+
"optional": true
|
| 2282 |
+
},
|
| 2283 |
+
"less": {
|
| 2284 |
+
"optional": true
|
| 2285 |
+
},
|
| 2286 |
+
"lightningcss": {
|
| 2287 |
+
"optional": true
|
| 2288 |
+
},
|
| 2289 |
+
"sass": {
|
| 2290 |
+
"optional": true
|
| 2291 |
+
},
|
| 2292 |
+
"sass-embedded": {
|
| 2293 |
+
"optional": true
|
| 2294 |
+
},
|
| 2295 |
+
"stylus": {
|
| 2296 |
+
"optional": true
|
| 2297 |
+
},
|
| 2298 |
+
"sugarss": {
|
| 2299 |
+
"optional": true
|
| 2300 |
+
},
|
| 2301 |
+
"terser": {
|
| 2302 |
+
"optional": true
|
| 2303 |
+
},
|
| 2304 |
+
"tsx": {
|
| 2305 |
+
"optional": true
|
| 2306 |
+
},
|
| 2307 |
+
"yaml": {
|
| 2308 |
+
"optional": true
|
| 2309 |
+
}
|
| 2310 |
+
}
|
| 2311 |
+
},
|
| 2312 |
+
"node_modules/vite-node": {
|
| 2313 |
+
"version": "3.2.4",
|
| 2314 |
+
"resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-3.2.4.tgz",
|
| 2315 |
+
"integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
|
| 2316 |
+
"dev": true,
|
| 2317 |
+
"license": "MIT",
|
| 2318 |
+
"dependencies": {
|
| 2319 |
+
"cac": "^6.7.14",
|
| 2320 |
+
"debug": "^4.4.1",
|
| 2321 |
+
"es-module-lexer": "^1.7.0",
|
| 2322 |
+
"pathe": "^2.0.3",
|
| 2323 |
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
|
| 2324 |
+
},
|
| 2325 |
+
"bin": {
|
| 2326 |
+
"vite-node": "vite-node.mjs"
|
| 2327 |
+
},
|
| 2328 |
+
"engines": {
|
| 2329 |
+
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
| 2330 |
+
},
|
| 2331 |
+
"funding": {
|
| 2332 |
+
"url": "https://opencollective.com/vitest"
|
| 2333 |
+
}
|
| 2334 |
+
},
|
| 2335 |
+
"node_modules/vitest": {
|
| 2336 |
+
"version": "3.2.4",
|
| 2337 |
+
"resolved": "https://registry.npmmirror.com/vitest/-/vitest-3.2.4.tgz",
|
| 2338 |
+
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
| 2339 |
+
"dev": true,
|
| 2340 |
+
"license": "MIT",
|
| 2341 |
+
"dependencies": {
|
| 2342 |
+
"@types/chai": "^5.2.2",
|
| 2343 |
+
"@vitest/expect": "3.2.4",
|
| 2344 |
+
"@vitest/mocker": "3.2.4",
|
| 2345 |
+
"@vitest/pretty-format": "^3.2.4",
|
| 2346 |
+
"@vitest/runner": "3.2.4",
|
| 2347 |
+
"@vitest/snapshot": "3.2.4",
|
| 2348 |
+
"@vitest/spy": "3.2.4",
|
| 2349 |
+
"@vitest/utils": "3.2.4",
|
| 2350 |
+
"chai": "^5.2.0",
|
| 2351 |
+
"debug": "^4.4.1",
|
| 2352 |
+
"expect-type": "^1.2.1",
|
| 2353 |
+
"magic-string": "^0.30.17",
|
| 2354 |
+
"pathe": "^2.0.3",
|
| 2355 |
+
"picomatch": "^4.0.2",
|
| 2356 |
+
"std-env": "^3.9.0",
|
| 2357 |
+
"tinybench": "^2.9.0",
|
| 2358 |
+
"tinyexec": "^0.3.2",
|
| 2359 |
+
"tinyglobby": "^0.2.14",
|
| 2360 |
+
"tinypool": "^1.1.1",
|
| 2361 |
+
"tinyrainbow": "^2.0.0",
|
| 2362 |
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
|
| 2363 |
+
"vite-node": "3.2.4",
|
| 2364 |
+
"why-is-node-running": "^2.3.0"
|
| 2365 |
+
},
|
| 2366 |
+
"bin": {
|
| 2367 |
+
"vitest": "vitest.mjs"
|
| 2368 |
+
},
|
| 2369 |
+
"engines": {
|
| 2370 |
+
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
| 2371 |
+
},
|
| 2372 |
+
"funding": {
|
| 2373 |
+
"url": "https://opencollective.com/vitest"
|
| 2374 |
+
},
|
| 2375 |
+
"peerDependencies": {
|
| 2376 |
+
"@edge-runtime/vm": "*",
|
| 2377 |
+
"@types/debug": "^4.1.12",
|
| 2378 |
+
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
| 2379 |
+
"@vitest/browser": "3.2.4",
|
| 2380 |
+
"@vitest/ui": "3.2.4",
|
| 2381 |
+
"happy-dom": "*",
|
| 2382 |
+
"jsdom": "*"
|
| 2383 |
+
},
|
| 2384 |
+
"peerDependenciesMeta": {
|
| 2385 |
+
"@edge-runtime/vm": {
|
| 2386 |
+
"optional": true
|
| 2387 |
+
},
|
| 2388 |
+
"@types/debug": {
|
| 2389 |
+
"optional": true
|
| 2390 |
+
},
|
| 2391 |
+
"@types/node": {
|
| 2392 |
+
"optional": true
|
| 2393 |
+
},
|
| 2394 |
+
"@vitest/browser": {
|
| 2395 |
+
"optional": true
|
| 2396 |
+
},
|
| 2397 |
+
"@vitest/ui": {
|
| 2398 |
+
"optional": true
|
| 2399 |
+
},
|
| 2400 |
+
"happy-dom": {
|
| 2401 |
+
"optional": true
|
| 2402 |
+
},
|
| 2403 |
+
"jsdom": {
|
| 2404 |
+
"optional": true
|
| 2405 |
+
}
|
| 2406 |
+
}
|
| 2407 |
+
},
|
| 2408 |
"node_modules/which": {
|
| 2409 |
"version": "2.0.2",
|
| 2410 |
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
|
|
|
|
| 2421 |
"node": ">= 8"
|
| 2422 |
}
|
| 2423 |
},
|
| 2424 |
+
"node_modules/why-is-node-running": {
|
| 2425 |
+
"version": "2.3.0",
|
| 2426 |
+
"resolved": "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
|
| 2427 |
+
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
|
| 2428 |
+
"dev": true,
|
| 2429 |
+
"license": "MIT",
|
| 2430 |
+
"dependencies": {
|
| 2431 |
+
"siginfo": "^2.0.0",
|
| 2432 |
+
"stackback": "0.0.2"
|
| 2433 |
+
},
|
| 2434 |
+
"bin": {
|
| 2435 |
+
"why-is-node-running": "cli.js"
|
| 2436 |
+
},
|
| 2437 |
+
"engines": {
|
| 2438 |
+
"node": ">=8"
|
| 2439 |
+
}
|
| 2440 |
+
},
|
| 2441 |
"node_modules/wrap-ansi": {
|
| 2442 |
"version": "8.1.0",
|
| 2443 |
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
package.json
CHANGED
|
@@ -4,6 +4,8 @@
|
|
| 4 |
"description": "Reverse proxy that exposes Codex Desktop Responses API as OpenAI-compatible /v1/chat/completions",
|
| 5 |
"type": "module",
|
| 6 |
"scripts": {
|
|
|
|
|
|
|
| 7 |
"dev": "tsx watch src/index.ts",
|
| 8 |
"dev:web": "cd web && npx vite",
|
| 9 |
"build:web": "cd web && npx vite build",
|
|
@@ -34,6 +36,7 @@
|
|
| 34 |
"@types/node": "^22.0.0",
|
| 35 |
"js-beautify": "^1.15.0",
|
| 36 |
"tsx": "^4.0.0",
|
| 37 |
-
"typescript": "^5.5.0"
|
|
|
|
| 38 |
}
|
| 39 |
}
|
|
|
|
| 4 |
"description": "Reverse proxy that exposes Codex Desktop Responses API as OpenAI-compatible /v1/chat/completions",
|
| 5 |
"type": "module",
|
| 6 |
"scripts": {
|
| 7 |
+
"test": "vitest run",
|
| 8 |
+
"test:watch": "vitest",
|
| 9 |
"dev": "tsx watch src/index.ts",
|
| 10 |
"dev:web": "cd web && npx vite",
|
| 11 |
"build:web": "cd web && npx vite build",
|
|
|
|
| 36 |
"@types/node": "^22.0.0",
|
| 37 |
"js-beautify": "^1.15.0",
|
| 38 |
"tsx": "^4.0.0",
|
| 39 |
+
"typescript": "^5.5.0",
|
| 40 |
+
"vitest": "^3.2.4"
|
| 41 |
}
|
| 42 |
}
|
src/auth/__tests__/account-pool.test.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Tests for AccountPool core scheduling logic.
|
| 3 |
+
*
|
| 4 |
+
* Uses vi.mock to stub filesystem and JWT utilities so tests run
|
| 5 |
+
* without actual data files or valid JWT tokens.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
| 9 |
+
|
| 10 |
+
// Mock fs before importing AccountPool
|
| 11 |
+
vi.mock("fs", () => ({
|
| 12 |
+
readFileSync: vi.fn(() => { throw new Error("ENOENT"); }),
|
| 13 |
+
writeFileSync: vi.fn(),
|
| 14 |
+
renameSync: vi.fn(),
|
| 15 |
+
existsSync: vi.fn(() => false),
|
| 16 |
+
mkdirSync: vi.fn(),
|
| 17 |
+
}));
|
| 18 |
+
|
| 19 |
+
// Mock config
|
| 20 |
+
vi.mock("../../config.js", () => ({
|
| 21 |
+
getConfig: vi.fn(() => ({
|
| 22 |
+
auth: {
|
| 23 |
+
jwt_token: null,
|
| 24 |
+
rotation_strategy: "least_used",
|
| 25 |
+
rate_limit_backoff_seconds: 60,
|
| 26 |
+
},
|
| 27 |
+
server: {
|
| 28 |
+
proxy_api_key: null,
|
| 29 |
+
},
|
| 30 |
+
})),
|
| 31 |
+
}));
|
| 32 |
+
|
| 33 |
+
// Mock JWT utilities — all tokens are "valid"
|
| 34 |
+
vi.mock("../jwt-utils.js", () => ({
|
| 35 |
+
decodeJwtPayload: vi.fn(() => ({ exp: Math.floor(Date.now() / 1000) + 3600 })),
|
| 36 |
+
extractChatGptAccountId: vi.fn((token: string) => `acct-${token.slice(0, 8)}`),
|
| 37 |
+
extractUserProfile: vi.fn((token: string) => ({
|
| 38 |
+
email: `${token.slice(0, 4)}@test.com`,
|
| 39 |
+
chatgpt_plan_type: "free",
|
| 40 |
+
})),
|
| 41 |
+
isTokenExpired: vi.fn(() => false),
|
| 42 |
+
}));
|
| 43 |
+
|
| 44 |
+
// Mock jitter to return the exact value (no randomness in tests)
|
| 45 |
+
vi.mock("../../utils/jitter.js", () => ({
|
| 46 |
+
jitter: vi.fn((val: number) => val),
|
| 47 |
+
}));
|
| 48 |
+
|
| 49 |
+
import { AccountPool } from "../account-pool.js";
|
| 50 |
+
import { getConfig } from "../../config.js";
|
| 51 |
+
import { isTokenExpired } from "../jwt-utils.js";
|
| 52 |
+
|
| 53 |
+
describe("AccountPool", () => {
|
| 54 |
+
let pool: AccountPool;
|
| 55 |
+
|
| 56 |
+
beforeEach(() => {
|
| 57 |
+
// Reset mock implementations to defaults (clearAllMocks only clears call history)
|
| 58 |
+
vi.mocked(isTokenExpired).mockReturnValue(false);
|
| 59 |
+
vi.mocked(getConfig).mockReturnValue({
|
| 60 |
+
auth: {
|
| 61 |
+
jwt_token: null,
|
| 62 |
+
rotation_strategy: "least_used",
|
| 63 |
+
rate_limit_backoff_seconds: 60,
|
| 64 |
+
},
|
| 65 |
+
server: { proxy_api_key: null },
|
| 66 |
+
} as ReturnType<typeof getConfig>);
|
| 67 |
+
pool = new AccountPool();
|
| 68 |
+
});
|
| 69 |
+
|
| 70 |
+
afterEach(() => {
|
| 71 |
+
pool.destroy();
|
| 72 |
+
});
|
| 73 |
+
|
| 74 |
+
describe("addAccount + acquire", () => {
|
| 75 |
+
it("adds an account and acquires it", () => {
|
| 76 |
+
pool.addAccount("token-aaa");
|
| 77 |
+
|
| 78 |
+
const acquired = pool.acquire();
|
| 79 |
+
expect(acquired).not.toBeNull();
|
| 80 |
+
expect(acquired!.token).toBe("token-aaa");
|
| 81 |
+
});
|
| 82 |
+
|
| 83 |
+
it("deduplicates by accountId", () => {
|
| 84 |
+
const id1 = pool.addAccount("token-aaa");
|
| 85 |
+
const id2 = pool.addAccount("token-aaa"); // same prefix → same accountId
|
| 86 |
+
|
| 87 |
+
expect(id1).toBe(id2);
|
| 88 |
+
});
|
| 89 |
+
|
| 90 |
+
it("returns null when no accounts exist", () => {
|
| 91 |
+
expect(pool.acquire()).toBeNull();
|
| 92 |
+
});
|
| 93 |
+
});
|
| 94 |
+
|
| 95 |
+
describe("least_used rotation", () => {
|
| 96 |
+
it("selects the account with lowest request_count", () => {
|
| 97 |
+
pool.addAccount("token-aaa");
|
| 98 |
+
pool.addAccount("token-bbb");
|
| 99 |
+
|
| 100 |
+
// Use account A once
|
| 101 |
+
const first = pool.acquire()!;
|
| 102 |
+
pool.release(first.entryId, { input_tokens: 10, output_tokens: 5 });
|
| 103 |
+
|
| 104 |
+
// Next acquire should pick the other account (0 requests)
|
| 105 |
+
const second = pool.acquire()!;
|
| 106 |
+
expect(second.entryId).not.toBe(first.entryId);
|
| 107 |
+
});
|
| 108 |
+
});
|
| 109 |
+
|
| 110 |
+
describe("round_robin rotation", () => {
|
| 111 |
+
it("cycles through accounts in order", () => {
|
| 112 |
+
vi.mocked(getConfig).mockReturnValue({
|
| 113 |
+
auth: {
|
| 114 |
+
jwt_token: null,
|
| 115 |
+
rotation_strategy: "round_robin",
|
| 116 |
+
rate_limit_backoff_seconds: 60,
|
| 117 |
+
},
|
| 118 |
+
server: { proxy_api_key: null },
|
| 119 |
+
} as ReturnType<typeof getConfig>);
|
| 120 |
+
|
| 121 |
+
// Create a fresh pool with round_robin config
|
| 122 |
+
const rrPool = new AccountPool();
|
| 123 |
+
rrPool.addAccount("token-aaa");
|
| 124 |
+
rrPool.addAccount("token-bbb");
|
| 125 |
+
|
| 126 |
+
const a1 = rrPool.acquire()!;
|
| 127 |
+
rrPool.release(a1.entryId);
|
| 128 |
+
|
| 129 |
+
const a2 = rrPool.acquire()!;
|
| 130 |
+
rrPool.release(a2.entryId);
|
| 131 |
+
|
| 132 |
+
const a3 = rrPool.acquire()!;
|
| 133 |
+
rrPool.release(a3.entryId);
|
| 134 |
+
|
| 135 |
+
// a3 should wrap around to same as a1
|
| 136 |
+
expect(a3.entryId).toBe(a1.entryId);
|
| 137 |
+
expect(a1.entryId).not.toBe(a2.entryId);
|
| 138 |
+
|
| 139 |
+
rrPool.destroy();
|
| 140 |
+
});
|
| 141 |
+
});
|
| 142 |
+
|
| 143 |
+
describe("release", () => {
|
| 144 |
+
it("increments request_count and token usage", () => {
|
| 145 |
+
pool.addAccount("token-aaa");
|
| 146 |
+
|
| 147 |
+
const acquired = pool.acquire()!;
|
| 148 |
+
pool.release(acquired.entryId, { input_tokens: 100, output_tokens: 50 });
|
| 149 |
+
|
| 150 |
+
const accounts = pool.getAccounts();
|
| 151 |
+
expect(accounts[0].usage.request_count).toBe(1);
|
| 152 |
+
expect(accounts[0].usage.input_tokens).toBe(100);
|
| 153 |
+
expect(accounts[0].usage.output_tokens).toBe(50);
|
| 154 |
+
expect(accounts[0].usage.last_used).not.toBeNull();
|
| 155 |
+
});
|
| 156 |
+
|
| 157 |
+
it("unlocks account after release", () => {
|
| 158 |
+
pool.addAccount("token-aaa");
|
| 159 |
+
|
| 160 |
+
const a1 = pool.acquire()!;
|
| 161 |
+
// While locked, acquire returns null (only 1 account)
|
| 162 |
+
expect(pool.acquire()).toBeNull();
|
| 163 |
+
|
| 164 |
+
pool.release(a1.entryId);
|
| 165 |
+
// After release, can acquire again
|
| 166 |
+
expect(pool.acquire()).not.toBeNull();
|
| 167 |
+
});
|
| 168 |
+
});
|
| 169 |
+
|
| 170 |
+
describe("markRateLimited", () => {
|
| 171 |
+
it("marks account as rate_limited and skips it in acquire", () => {
|
| 172 |
+
pool.addAccount("token-aaa");
|
| 173 |
+
pool.addAccount("token-bbb");
|
| 174 |
+
|
| 175 |
+
const first = pool.acquire()!;
|
| 176 |
+
pool.markRateLimited(first.entryId);
|
| 177 |
+
|
| 178 |
+
// Pool summary should show 1 rate_limited
|
| 179 |
+
const summary = pool.getPoolSummary();
|
| 180 |
+
expect(summary.rate_limited).toBe(1);
|
| 181 |
+
expect(summary.active).toBe(1);
|
| 182 |
+
|
| 183 |
+
// Next acquire should skip the rate-limited account
|
| 184 |
+
const second = pool.acquire()!;
|
| 185 |
+
expect(second.entryId).not.toBe(first.entryId);
|
| 186 |
+
});
|
| 187 |
+
|
| 188 |
+
it("countRequest option increments usage on 429", () => {
|
| 189 |
+
pool.addAccount("token-aaa");
|
| 190 |
+
|
| 191 |
+
const acquired = pool.acquire()!;
|
| 192 |
+
pool.markRateLimited(acquired.entryId, { countRequest: true });
|
| 193 |
+
|
| 194 |
+
const accounts = pool.getAccounts();
|
| 195 |
+
expect(accounts[0].usage.request_count).toBe(1);
|
| 196 |
+
});
|
| 197 |
+
|
| 198 |
+
it("auto-recovers after rate_limit_until passes", () => {
|
| 199 |
+
pool.addAccount("token-aaa");
|
| 200 |
+
|
| 201 |
+
const acquired = pool.acquire()!;
|
| 202 |
+
// Set rate limit to already expired
|
| 203 |
+
pool.markRateLimited(acquired.entryId, { retryAfterSec: -1 });
|
| 204 |
+
|
| 205 |
+
// refreshStatus should detect the expired rate_limit_until
|
| 206 |
+
const summary = pool.getPoolSummary();
|
| 207 |
+
expect(summary.active).toBe(1);
|
| 208 |
+
expect(summary.rate_limited).toBe(0);
|
| 209 |
+
});
|
| 210 |
+
});
|
| 211 |
+
|
| 212 |
+
describe("stale lock auto-release", () => {
|
| 213 |
+
it("releases locks older than 5 minutes", () => {
|
| 214 |
+
pool.addAccount("token-aaa");
|
| 215 |
+
|
| 216 |
+
const acquired = pool.acquire()!;
|
| 217 |
+
|
| 218 |
+
// Manually backdate the lock by manipulating the acquireLocks map
|
| 219 |
+
// Access private field for testing — unavoidable for TTL tests
|
| 220 |
+
const locks = (pool as unknown as { acquireLocks: Map<string, number> }).acquireLocks;
|
| 221 |
+
locks.set(acquired.entryId, Date.now() - 6 * 60 * 1000); // 6 minutes ago
|
| 222 |
+
|
| 223 |
+
// Next acquire should auto-release the stale lock and return the same account
|
| 224 |
+
const reacquired = pool.acquire()!;
|
| 225 |
+
expect(reacquired).not.toBeNull();
|
| 226 |
+
expect(reacquired.entryId).toBe(acquired.entryId);
|
| 227 |
+
});
|
| 228 |
+
});
|
| 229 |
+
|
| 230 |
+
describe("expired tokens", () => {
|
| 231 |
+
it("skips expired accounts in acquire", () => {
|
| 232 |
+
vi.mocked(isTokenExpired).mockReturnValue(true);
|
| 233 |
+
pool.addAccount("token-expired");
|
| 234 |
+
|
| 235 |
+
expect(pool.acquire()).toBeNull();
|
| 236 |
+
expect(pool.getPoolSummary().expired).toBe(1);
|
| 237 |
+
});
|
| 238 |
+
});
|
| 239 |
+
|
| 240 |
+
describe("removeAccount", () => {
|
| 241 |
+
it("removes an account and clears its lock", () => {
|
| 242 |
+
pool.addAccount("token-aaa");
|
| 243 |
+
|
| 244 |
+
const acquired = pool.acquire()!;
|
| 245 |
+
pool.removeAccount(acquired.entryId);
|
| 246 |
+
|
| 247 |
+
expect(pool.getPoolSummary().total).toBe(0);
|
| 248 |
+
expect(pool.acquire()).toBeNull();
|
| 249 |
+
});
|
| 250 |
+
});
|
| 251 |
+
|
| 252 |
+
describe("resetUsage", () => {
|
| 253 |
+
it("resets counters to zero", () => {
|
| 254 |
+
pool.addAccount("token-aaa");
|
| 255 |
+
|
| 256 |
+
const acquired = pool.acquire()!;
|
| 257 |
+
pool.release(acquired.entryId, { input_tokens: 100, output_tokens: 50 });
|
| 258 |
+
pool.resetUsage(acquired.entryId);
|
| 259 |
+
|
| 260 |
+
const accounts = pool.getAccounts();
|
| 261 |
+
expect(accounts[0].usage.request_count).toBe(0);
|
| 262 |
+
expect(accounts[0].usage.input_tokens).toBe(0);
|
| 263 |
+
expect(accounts[0].usage.output_tokens).toBe(0);
|
| 264 |
+
});
|
| 265 |
+
});
|
| 266 |
+
|
| 267 |
+
describe("validateProxyApiKey", () => {
|
| 268 |
+
it("validates per-account proxy API key", () => {
|
| 269 |
+
pool.addAccount("token-aaa");
|
| 270 |
+
|
| 271 |
+
const accounts = pool.getAccounts();
|
| 272 |
+
// Each account gets a generated proxyApiKey — we can't predict it,
|
| 273 |
+
// but we can read it and validate
|
| 274 |
+
const entry = pool.getEntry(accounts[0].id)!;
|
| 275 |
+
expect(pool.validateProxyApiKey(entry.proxyApiKey)).toBe(true);
|
| 276 |
+
expect(pool.validateProxyApiKey("wrong-key")).toBe(false);
|
| 277 |
+
});
|
| 278 |
+
|
| 279 |
+
it("validates config-level proxy API key", () => {
|
| 280 |
+
vi.mocked(getConfig).mockReturnValue({
|
| 281 |
+
auth: {
|
| 282 |
+
jwt_token: null,
|
| 283 |
+
rotation_strategy: "least_used",
|
| 284 |
+
rate_limit_backoff_seconds: 60,
|
| 285 |
+
},
|
| 286 |
+
server: { proxy_api_key: "global-key-123" },
|
| 287 |
+
} as ReturnType<typeof getConfig>);
|
| 288 |
+
|
| 289 |
+
expect(pool.validateProxyApiKey("global-key-123")).toBe(true);
|
| 290 |
+
});
|
| 291 |
+
});
|
| 292 |
+
});
|
src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { loadConfig, loadFingerprint, getConfig } from "./config.js";
|
|
| 4 |
import { AccountPool } from "./auth/account-pool.js";
|
| 5 |
import { RefreshScheduler } from "./auth/refresh-scheduler.js";
|
| 6 |
import { SessionManager } from "./session/manager.js";
|
|
|
|
| 7 |
import { logger } from "./middleware/logger.js";
|
| 8 |
import { errorHandler } from "./middleware/error-handler.js";
|
| 9 |
import { createAuthRoutes } from "./routes/auth.js";
|
|
@@ -48,6 +49,7 @@ async function main() {
|
|
| 48 |
const app = new Hono();
|
| 49 |
|
| 50 |
// Global middleware
|
|
|
|
| 51 |
app.use("*", logger);
|
| 52 |
app.use("*", errorHandler);
|
| 53 |
|
|
|
|
| 4 |
import { AccountPool } from "./auth/account-pool.js";
|
| 5 |
import { RefreshScheduler } from "./auth/refresh-scheduler.js";
|
| 6 |
import { SessionManager } from "./session/manager.js";
|
| 7 |
+
import { requestId } from "./middleware/request-id.js";
|
| 8 |
import { logger } from "./middleware/logger.js";
|
| 9 |
import { errorHandler } from "./middleware/error-handler.js";
|
| 10 |
import { createAuthRoutes } from "./routes/auth.js";
|
|
|
|
| 49 |
const app = new Hono();
|
| 50 |
|
| 51 |
// Global middleware
|
| 52 |
+
app.use("*", requestId);
|
| 53 |
app.use("*", logger);
|
| 54 |
app.use("*", errorHandler);
|
| 55 |
|
src/proxy/__tests__/codex-api.test.ts
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Tests for CodexApi SSE parsing.
|
| 3 |
+
*
|
| 4 |
+
* parseStream() is the most fragile code path — it processes real-time
|
| 5 |
+
* byte streams from curl where chunks can split at any boundary.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
import { describe, it, expect } from "vitest";
|
| 9 |
+
import { CodexApi, type CodexSSEEvent } from "../codex-api.js";
|
| 10 |
+
|
| 11 |
+
/** Create a Response whose body emits the given string chunks sequentially. */
|
| 12 |
+
function mockResponse(...chunks: string[]): Response {
|
| 13 |
+
const encoder = new TextEncoder();
|
| 14 |
+
let idx = 0;
|
| 15 |
+
const stream = new ReadableStream<Uint8Array>({
|
| 16 |
+
pull(controller) {
|
| 17 |
+
if (idx < chunks.length) {
|
| 18 |
+
controller.enqueue(encoder.encode(chunks[idx]));
|
| 19 |
+
idx++;
|
| 20 |
+
} else {
|
| 21 |
+
controller.close();
|
| 22 |
+
}
|
| 23 |
+
},
|
| 24 |
+
});
|
| 25 |
+
return new Response(stream);
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/** Collect all events from parseStream into an array. */
|
| 29 |
+
async function collectEvents(api: CodexApi, response: Response): Promise<CodexSSEEvent[]> {
|
| 30 |
+
const events: CodexSSEEvent[] = [];
|
| 31 |
+
for await (const evt of api.parseStream(response)) {
|
| 32 |
+
events.push(evt);
|
| 33 |
+
}
|
| 34 |
+
return events;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
// CodexApi constructor requires a token — value is irrelevant for parsing tests
|
| 38 |
+
function createApi(): CodexApi {
|
| 39 |
+
return new CodexApi("test-token", null);
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
describe("CodexApi.parseStream", () => {
|
| 43 |
+
it("parses a complete SSE event in a single chunk", async () => {
|
| 44 |
+
const api = createApi();
|
| 45 |
+
const response = mockResponse(
|
| 46 |
+
'event: response.output_text.delta\ndata: {"delta":"Hello"}\n\n',
|
| 47 |
+
);
|
| 48 |
+
|
| 49 |
+
const events = await collectEvents(api, response);
|
| 50 |
+
expect(events).toHaveLength(1);
|
| 51 |
+
expect(events[0].event).toBe("response.output_text.delta");
|
| 52 |
+
expect(events[0].data).toEqual({ delta: "Hello" });
|
| 53 |
+
});
|
| 54 |
+
|
| 55 |
+
it("handles multiple events in a single chunk", async () => {
|
| 56 |
+
const api = createApi();
|
| 57 |
+
const response = mockResponse(
|
| 58 |
+
'event: response.created\ndata: {"response":{"id":"resp_1"}}\n\n' +
|
| 59 |
+
'event: response.output_text.delta\ndata: {"delta":"Hi"}\n\n' +
|
| 60 |
+
'event: response.completed\ndata: {"response":{"id":"resp_1","usage":{"input_tokens":10,"output_tokens":5}}}\n\n',
|
| 61 |
+
);
|
| 62 |
+
|
| 63 |
+
const events = await collectEvents(api, response);
|
| 64 |
+
expect(events).toHaveLength(3);
|
| 65 |
+
expect(events[0].event).toBe("response.created");
|
| 66 |
+
expect(events[1].event).toBe("response.output_text.delta");
|
| 67 |
+
expect(events[2].event).toBe("response.completed");
|
| 68 |
+
});
|
| 69 |
+
|
| 70 |
+
it("reassembles events split across chunk boundaries", async () => {
|
| 71 |
+
const api = createApi();
|
| 72 |
+
// Split in the middle of the JSON data
|
| 73 |
+
const response = mockResponse(
|
| 74 |
+
'event: response.output_text.delta\ndata: {"del',
|
| 75 |
+
'ta":"world"}\n\n',
|
| 76 |
+
);
|
| 77 |
+
|
| 78 |
+
const events = await collectEvents(api, response);
|
| 79 |
+
expect(events).toHaveLength(1);
|
| 80 |
+
expect(events[0].data).toEqual({ delta: "world" });
|
| 81 |
+
});
|
| 82 |
+
|
| 83 |
+
it("handles chunk split at \\n\\n boundary", async () => {
|
| 84 |
+
const api = createApi();
|
| 85 |
+
// First chunk ends with first \n, second starts with second \n
|
| 86 |
+
const response = mockResponse(
|
| 87 |
+
'event: response.output_text.delta\ndata: {"delta":"a"}\n',
|
| 88 |
+
'\nevent: response.output_text.delta\ndata: {"delta":"b"}\n\n',
|
| 89 |
+
);
|
| 90 |
+
|
| 91 |
+
const events = await collectEvents(api, response);
|
| 92 |
+
expect(events).toHaveLength(2);
|
| 93 |
+
expect(events[0].data).toEqual({ delta: "a" });
|
| 94 |
+
expect(events[1].data).toEqual({ delta: "b" });
|
| 95 |
+
});
|
| 96 |
+
|
| 97 |
+
it("handles many small single-character chunks", async () => {
|
| 98 |
+
const api = createApi();
|
| 99 |
+
const full = 'event: response.output_text.delta\ndata: {"delta":"x"}\n\n';
|
| 100 |
+
// Split into individual characters
|
| 101 |
+
const chunks = full.split("");
|
| 102 |
+
const response = mockResponse(...chunks);
|
| 103 |
+
|
| 104 |
+
const events = await collectEvents(api, response);
|
| 105 |
+
expect(events).toHaveLength(1);
|
| 106 |
+
expect(events[0].data).toEqual({ delta: "x" });
|
| 107 |
+
});
|
| 108 |
+
|
| 109 |
+
it("skips [DONE] marker without crashing", async () => {
|
| 110 |
+
const api = createApi();
|
| 111 |
+
const response = mockResponse(
|
| 112 |
+
'event: response.output_text.delta\ndata: {"delta":"hi"}\n\n' +
|
| 113 |
+
"data: [DONE]\n\n",
|
| 114 |
+
);
|
| 115 |
+
|
| 116 |
+
const events = await collectEvents(api, response);
|
| 117 |
+
expect(events).toHaveLength(1);
|
| 118 |
+
expect(events[0].data).toEqual({ delta: "hi" });
|
| 119 |
+
});
|
| 120 |
+
|
| 121 |
+
it("returns raw string when data is not valid JSON", async () => {
|
| 122 |
+
const api = createApi();
|
| 123 |
+
const response = mockResponse(
|
| 124 |
+
'event: response.output_text.delta\ndata: not-json-at-all\n\n',
|
| 125 |
+
);
|
| 126 |
+
|
| 127 |
+
const events = await collectEvents(api, response);
|
| 128 |
+
expect(events).toHaveLength(1);
|
| 129 |
+
expect(events[0].data).toBe("not-json-at-all");
|
| 130 |
+
});
|
| 131 |
+
|
| 132 |
+
it("handles malformed JSON (unclosed brace) gracefully", async () => {
|
| 133 |
+
const api = createApi();
|
| 134 |
+
const response = mockResponse(
|
| 135 |
+
'event: response.output_text.delta\ndata: {"delta":"unclosed\n\n',
|
| 136 |
+
);
|
| 137 |
+
|
| 138 |
+
const events = await collectEvents(api, response);
|
| 139 |
+
expect(events).toHaveLength(1);
|
| 140 |
+
// Should not throw — falls through to raw string
|
| 141 |
+
expect(typeof events[0].data).toBe("string");
|
| 142 |
+
});
|
| 143 |
+
|
| 144 |
+
it("skips empty blocks between events", async () => {
|
| 145 |
+
const api = createApi();
|
| 146 |
+
const response = mockResponse(
|
| 147 |
+
'event: response.output_text.delta\ndata: {"delta":"a"}\n\n' +
|
| 148 |
+
"\n\n" + // empty block
|
| 149 |
+
'event: response.output_text.delta\ndata: {"delta":"b"}\n\n',
|
| 150 |
+
);
|
| 151 |
+
|
| 152 |
+
const events = await collectEvents(api, response);
|
| 153 |
+
expect(events).toHaveLength(2);
|
| 154 |
+
});
|
| 155 |
+
|
| 156 |
+
it("processes remaining buffer after stream ends", async () => {
|
| 157 |
+
const api = createApi();
|
| 158 |
+
// No trailing \n\n — the event is only in the residual buffer
|
| 159 |
+
const response = mockResponse(
|
| 160 |
+
'event: response.output_text.delta\ndata: {"delta":"last"}',
|
| 161 |
+
);
|
| 162 |
+
|
| 163 |
+
const events = await collectEvents(api, response);
|
| 164 |
+
expect(events).toHaveLength(1);
|
| 165 |
+
expect(events[0].data).toEqual({ delta: "last" });
|
| 166 |
+
});
|
| 167 |
+
|
| 168 |
+
it("handles multi-line data fields", async () => {
|
| 169 |
+
const api = createApi();
|
| 170 |
+
const response = mockResponse(
|
| 171 |
+
'event: response.output_text.delta\ndata: {"delta":\n' +
|
| 172 |
+
'data: "multi-line"}\n\n',
|
| 173 |
+
);
|
| 174 |
+
|
| 175 |
+
const events = await collectEvents(api, response);
|
| 176 |
+
expect(events).toHaveLength(1);
|
| 177 |
+
// data lines are joined with \n: '{"delta":\n"multi-line"}'
|
| 178 |
+
expect(events[0].data).toEqual({ delta: "multi-line" });
|
| 179 |
+
});
|
| 180 |
+
|
| 181 |
+
it("returns null body error", async () => {
|
| 182 |
+
const api = createApi();
|
| 183 |
+
// Create a response with null body
|
| 184 |
+
const response = new Response(null);
|
| 185 |
+
|
| 186 |
+
await expect(async () => {
|
| 187 |
+
await collectEvents(api, response);
|
| 188 |
+
}).rejects.toThrow("Response body is null");
|
| 189 |
+
});
|
| 190 |
+
|
| 191 |
+
it("throws on buffer overflow (>10MB)", async () => {
|
| 192 |
+
const api = createApi();
|
| 193 |
+
// Create a chunk that exceeds the 10MB SSE buffer limit
|
| 194 |
+
const hugeData = "x".repeat(11 * 1024 * 1024);
|
| 195 |
+
const response = mockResponse(hugeData);
|
| 196 |
+
|
| 197 |
+
await expect(async () => {
|
| 198 |
+
await collectEvents(api, response);
|
| 199 |
+
}).rejects.toThrow("SSE buffer exceeded");
|
| 200 |
+
});
|
| 201 |
+
});
|
src/routes/web.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { readFileSync, existsSync } from "fs";
|
|
| 4 |
import { resolve } from "path";
|
| 5 |
import type { AccountPool } from "../auth/account-pool.js";
|
| 6 |
import { getConfig, getFingerprint } from "../config.js";
|
| 7 |
-
import { getUpdateState } from "../update-checker.js";
|
| 8 |
|
| 9 |
export function createWebRoutes(accountPool: AccountPool): Hono {
|
| 10 |
const app = new Hono();
|
|
@@ -27,14 +26,11 @@ export function createWebRoutes(accountPool: AccountPool): Hono {
|
|
| 27 |
|
| 28 |
app.get("/health", async (c) => {
|
| 29 |
const authenticated = accountPool.isAuthenticated();
|
| 30 |
-
const userInfo = accountPool.getUserInfo();
|
| 31 |
const poolSummary = accountPool.getPoolSummary();
|
| 32 |
return c.json({
|
| 33 |
status: "ok",
|
| 34 |
authenticated,
|
| 35 |
-
|
| 36 |
-
pool: poolSummary,
|
| 37 |
-
update: getUpdateState(),
|
| 38 |
timestamp: new Date().toISOString(),
|
| 39 |
});
|
| 40 |
});
|
|
|
|
| 4 |
import { resolve } from "path";
|
| 5 |
import type { AccountPool } from "../auth/account-pool.js";
|
| 6 |
import { getConfig, getFingerprint } from "../config.js";
|
|
|
|
| 7 |
|
| 8 |
export function createWebRoutes(accountPool: AccountPool): Hono {
|
| 9 |
const app = new Hono();
|
|
|
|
| 26 |
|
| 27 |
app.get("/health", async (c) => {
|
| 28 |
const authenticated = accountPool.isAuthenticated();
|
|
|
|
| 29 |
const poolSummary = accountPool.getPoolSummary();
|
| 30 |
return c.json({
|
| 31 |
status: "ok",
|
| 32 |
authenticated,
|
| 33 |
+
pool: { total: poolSummary.total, active: poolSummary.active },
|
|
|
|
|
|
|
| 34 |
timestamp: new Date().toISOString(),
|
| 35 |
});
|
| 36 |
});
|
src/translation/__tests__/codex-event-extractor.test.ts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Tests for parseCodexEvent — the shared event type parser.
|
| 3 |
+
*
|
| 4 |
+
* Tests the discriminated union mapping from raw SSE events to typed events.
|
| 5 |
+
* This is the IR hub of the hub-and-spoke translation architecture.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
import { describe, it, expect } from "vitest";
|
| 9 |
+
import { parseCodexEvent } from "../../types/codex-events.js";
|
| 10 |
+
import type { CodexSSEEvent } from "../../proxy/codex-api.js";
|
| 11 |
+
|
| 12 |
+
describe("parseCodexEvent", () => {
|
| 13 |
+
it("parses response.created with id", () => {
|
| 14 |
+
const raw: CodexSSEEvent = {
|
| 15 |
+
event: "response.created",
|
| 16 |
+
data: { response: { id: "resp_abc123" } },
|
| 17 |
+
};
|
| 18 |
+
const typed = parseCodexEvent(raw);
|
| 19 |
+
expect(typed.type).toBe("response.created");
|
| 20 |
+
if (typed.type === "response.created") {
|
| 21 |
+
expect(typed.response.id).toBe("resp_abc123");
|
| 22 |
+
}
|
| 23 |
+
});
|
| 24 |
+
|
| 25 |
+
it("parses response.in_progress", () => {
|
| 26 |
+
const raw: CodexSSEEvent = {
|
| 27 |
+
event: "response.in_progress",
|
| 28 |
+
data: { response: { id: "resp_abc123" } },
|
| 29 |
+
};
|
| 30 |
+
const typed = parseCodexEvent(raw);
|
| 31 |
+
expect(typed.type).toBe("response.in_progress");
|
| 32 |
+
if (typed.type === "response.in_progress") {
|
| 33 |
+
expect(typed.response.id).toBe("resp_abc123");
|
| 34 |
+
}
|
| 35 |
+
});
|
| 36 |
+
|
| 37 |
+
it("parses response.output_text.delta", () => {
|
| 38 |
+
const raw: CodexSSEEvent = {
|
| 39 |
+
event: "response.output_text.delta",
|
| 40 |
+
data: { delta: "Hello, world!" },
|
| 41 |
+
};
|
| 42 |
+
const typed = parseCodexEvent(raw);
|
| 43 |
+
expect(typed.type).toBe("response.output_text.delta");
|
| 44 |
+
if (typed.type === "response.output_text.delta") {
|
| 45 |
+
expect(typed.delta).toBe("Hello, world!");
|
| 46 |
+
}
|
| 47 |
+
});
|
| 48 |
+
|
| 49 |
+
it("parses response.output_text.done", () => {
|
| 50 |
+
const raw: CodexSSEEvent = {
|
| 51 |
+
event: "response.output_text.done",
|
| 52 |
+
data: { text: "Complete response text" },
|
| 53 |
+
};
|
| 54 |
+
const typed = parseCodexEvent(raw);
|
| 55 |
+
expect(typed.type).toBe("response.output_text.done");
|
| 56 |
+
if (typed.type === "response.output_text.done") {
|
| 57 |
+
expect(typed.text).toBe("Complete response text");
|
| 58 |
+
}
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
+
it("parses response.completed with usage", () => {
|
| 62 |
+
const raw: CodexSSEEvent = {
|
| 63 |
+
event: "response.completed",
|
| 64 |
+
data: {
|
| 65 |
+
response: {
|
| 66 |
+
id: "resp_abc123",
|
| 67 |
+
usage: { input_tokens: 150, output_tokens: 42 },
|
| 68 |
+
},
|
| 69 |
+
},
|
| 70 |
+
};
|
| 71 |
+
const typed = parseCodexEvent(raw);
|
| 72 |
+
expect(typed.type).toBe("response.completed");
|
| 73 |
+
if (typed.type === "response.completed") {
|
| 74 |
+
expect(typed.response.id).toBe("resp_abc123");
|
| 75 |
+
expect(typed.response.usage).toEqual({
|
| 76 |
+
input_tokens: 150,
|
| 77 |
+
output_tokens: 42,
|
| 78 |
+
});
|
| 79 |
+
}
|
| 80 |
+
});
|
| 81 |
+
|
| 82 |
+
it("parses response.completed without usage", () => {
|
| 83 |
+
const raw: CodexSSEEvent = {
|
| 84 |
+
event: "response.completed",
|
| 85 |
+
data: { response: { id: "resp_abc123" } },
|
| 86 |
+
};
|
| 87 |
+
const typed = parseCodexEvent(raw);
|
| 88 |
+
expect(typed.type).toBe("response.completed");
|
| 89 |
+
if (typed.type === "response.completed") {
|
| 90 |
+
expect(typed.response.usage).toBeUndefined();
|
| 91 |
+
}
|
| 92 |
+
});
|
| 93 |
+
|
| 94 |
+
it("returns unknown for unrecognized event types", () => {
|
| 95 |
+
const raw: CodexSSEEvent = {
|
| 96 |
+
event: "response.some_future_event",
|
| 97 |
+
data: { foo: "bar" },
|
| 98 |
+
};
|
| 99 |
+
const typed = parseCodexEvent(raw);
|
| 100 |
+
expect(typed.type).toBe("unknown");
|
| 101 |
+
if (typed.type === "unknown") {
|
| 102 |
+
expect(typed.raw).toEqual({ foo: "bar" });
|
| 103 |
+
}
|
| 104 |
+
});
|
| 105 |
+
|
| 106 |
+
it("returns unknown when response.created has no response object", () => {
|
| 107 |
+
const raw: CodexSSEEvent = {
|
| 108 |
+
event: "response.created",
|
| 109 |
+
data: "not an object",
|
| 110 |
+
};
|
| 111 |
+
const typed = parseCodexEvent(raw);
|
| 112 |
+
expect(typed.type).toBe("unknown");
|
| 113 |
+
});
|
| 114 |
+
|
| 115 |
+
it("returns unknown when response.created data has no response field", () => {
|
| 116 |
+
const raw: CodexSSEEvent = {
|
| 117 |
+
event: "response.created",
|
| 118 |
+
data: { something_else: true },
|
| 119 |
+
};
|
| 120 |
+
const typed = parseCodexEvent(raw);
|
| 121 |
+
expect(typed.type).toBe("unknown");
|
| 122 |
+
});
|
| 123 |
+
|
| 124 |
+
it("returns unknown when delta is not a string", () => {
|
| 125 |
+
const raw: CodexSSEEvent = {
|
| 126 |
+
event: "response.output_text.delta",
|
| 127 |
+
data: { delta: 123 },
|
| 128 |
+
};
|
| 129 |
+
const typed = parseCodexEvent(raw);
|
| 130 |
+
expect(typed.type).toBe("unknown");
|
| 131 |
+
});
|
| 132 |
+
|
| 133 |
+
it("handles empty delta string", () => {
|
| 134 |
+
const raw: CodexSSEEvent = {
|
| 135 |
+
event: "response.output_text.delta",
|
| 136 |
+
data: { delta: "" },
|
| 137 |
+
};
|
| 138 |
+
const typed = parseCodexEvent(raw);
|
| 139 |
+
expect(typed.type).toBe("response.output_text.delta");
|
| 140 |
+
if (typed.type === "response.output_text.delta") {
|
| 141 |
+
expect(typed.delta).toBe("");
|
| 142 |
+
}
|
| 143 |
+
});
|
| 144 |
+
|
| 145 |
+
it("defaults usage token counts to 0 for non-numeric values", () => {
|
| 146 |
+
const raw: CodexSSEEvent = {
|
| 147 |
+
event: "response.completed",
|
| 148 |
+
data: {
|
| 149 |
+
response: {
|
| 150 |
+
id: "resp_1",
|
| 151 |
+
usage: { input_tokens: "not a number", output_tokens: null },
|
| 152 |
+
},
|
| 153 |
+
},
|
| 154 |
+
};
|
| 155 |
+
const typed = parseCodexEvent(raw);
|
| 156 |
+
expect(typed.type).toBe("response.completed");
|
| 157 |
+
if (typed.type === "response.completed") {
|
| 158 |
+
expect(typed.response.usage).toEqual({
|
| 159 |
+
input_tokens: 0,
|
| 160 |
+
output_tokens: 0,
|
| 161 |
+
});
|
| 162 |
+
}
|
| 163 |
+
});
|
| 164 |
+
|
| 165 |
+
it("handles null data", () => {
|
| 166 |
+
const raw: CodexSSEEvent = {
|
| 167 |
+
event: "response.created",
|
| 168 |
+
data: null,
|
| 169 |
+
};
|
| 170 |
+
const typed = parseCodexEvent(raw);
|
| 171 |
+
expect(typed.type).toBe("unknown");
|
| 172 |
+
});
|
| 173 |
+
|
| 174 |
+
it("handles array data", () => {
|
| 175 |
+
const raw: CodexSSEEvent = {
|
| 176 |
+
event: "response.output_text.delta",
|
| 177 |
+
data: [1, 2, 3],
|
| 178 |
+
};
|
| 179 |
+
const typed = parseCodexEvent(raw);
|
| 180 |
+
expect(typed.type).toBe("unknown");
|
| 181 |
+
});
|
| 182 |
+
});
|
vitest.config.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defineConfig } from "vitest/config";
|
| 2 |
+
|
| 3 |
+
export default defineConfig({
|
| 4 |
+
test: {
|
| 5 |
+
root: "src",
|
| 6 |
+
environment: "node",
|
| 7 |
+
},
|
| 8 |
+
});
|