@chenpu17/cc-gw 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -2
- package/package.json +3 -2
- package/src/cli/dist/index.js +20 -2
- package/src/server/dist/index.js +150 -43
- package/src/web/dist/assets/{About-R4GuiAOC.js → About-BkGxQ3Pv.js} +2 -2
- package/src/web/dist/assets/{ApiKeys-CNNwIRTy.js → ApiKeys-GdImp523.js} +1 -1
- package/src/web/dist/assets/{Button-CgdNhVeu.js → Button-BkhovQFd.js} +1 -1
- package/src/web/dist/assets/{Dashboard-U1EC6qmF.js → Dashboard-DxSNZwZc.js} +1 -1
- package/src/web/dist/assets/{FormField-DJjnoGU0.js → FormField-C-bAE13W.js} +1 -1
- package/src/web/dist/assets/{Help-COAfsR6K.js → Help-Bj3HXV4H.js} +1 -1
- package/src/web/dist/assets/{Input-CkTJl-fF.js → Input-B6cOxhbI.js} +1 -1
- package/src/web/dist/assets/{Login-BbRStE3M.js → Login-Btsbo17f.js} +1 -1
- package/src/web/dist/assets/Logs-72HRZmFi.js +1 -0
- package/src/web/dist/assets/{ModelManagement-BWX0w6Wu.js → ModelManagement-cuAzyPgP.js} +1 -1
- package/src/web/dist/assets/{PageSection-BT-depe5.js → PageSection-Bq4tdag3.js} +1 -1
- package/src/web/dist/assets/Settings-DPvX1pD_.js +11 -0
- package/src/web/dist/assets/{StatusBadge-CgBAXD_S.js → StatusBadge-P00M_NBZ.js} +1 -1
- package/src/web/dist/assets/{copy-OD9YQ85H.js → copy-D321KBhI.js} +1 -1
- package/src/web/dist/assets/{index-DVBy-Kka.js → index-BLBh7aj6.js} +1 -1
- package/src/web/dist/assets/index-DEa23YLm.css +1 -0
- package/src/web/dist/assets/{index-3UByifOG.js → index-DP6DzFEd.js} +30 -30
- package/src/web/dist/assets/{info-DAG4KwRm.js → info-CADQNr0Q.js} +1 -1
- package/src/web/dist/assets/{useApiQuery-7KXAW9hB.js → useApiQuery-C5jmZPyb.js} +1 -1
- package/src/web/dist/index.html +2 -2
- package/src/web/dist/assets/Logs-C-7diPqf.js +0 -1
- package/src/web/dist/assets/Settings-CLM0Srx1.js +0 -1
- package/src/web/dist/assets/index-BFd07aus.css +0 -1
package/README.md
CHANGED
|
@@ -166,7 +166,74 @@ export CC_GW_ANTHROPIC_BETA_ALL=claude-code-20250219,interleaved-thinking-2025-0
|
|
|
166
166
|
|
|
167
167
|
然后运行 `direnv allow` 自动加载。
|
|
168
168
|
|
|
169
|
-
##### 6.3
|
|
169
|
+
##### 6.3 HTTPS 配置
|
|
170
|
+
|
|
171
|
+
cc-gw 支持同时启动 HTTP 和 HTTPS 服务。
|
|
172
|
+
|
|
173
|
+
**默认配置**:
|
|
174
|
+
- HTTP: 端口 `4100`(**默认启用**,推荐用于本地开发)
|
|
175
|
+
- HTTPS: 端口 `4443`(**默认关闭**)
|
|
176
|
+
- 两个协议可独立启用/禁用,但**至少要保持一个启用**
|
|
177
|
+
|
|
178
|
+
⚠️ **重要提示:关于 HTTPS 证书**
|
|
179
|
+
|
|
180
|
+
- **自签名证书无效**:Claude Code 和大多数 AI 工具无法信任自签名证书,会导致 "Unable to connect to API" 错误
|
|
181
|
+
- **推荐方案**:本地开发环境建议使用 HTTP 协议(`127.0.0.1` 本地访问非常安全)
|
|
182
|
+
- **如需 HTTPS**:请使用受信任 CA(如 Let's Encrypt)签发的正式证书,或配置反向代理(如 Nginx/Caddy)处理 HTTPS
|
|
183
|
+
|
|
184
|
+
**手动配置 HTTPS(通过配置文件)**:
|
|
185
|
+
|
|
186
|
+
编辑 `~/.cc-gw/config.json`:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"http": {
|
|
191
|
+
"enabled": true,
|
|
192
|
+
"port": 4100,
|
|
193
|
+
"host": "127.0.0.1"
|
|
194
|
+
},
|
|
195
|
+
"https": {
|
|
196
|
+
"enabled": true,
|
|
197
|
+
"port": 4443,
|
|
198
|
+
"host": "127.0.0.1",
|
|
199
|
+
"keyPath": "/path/to/your/ssl/key.pem",
|
|
200
|
+
"certPath": "/path/to/your/ssl/cert.pem",
|
|
201
|
+
"caPath": ""
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**使用 HTTPS 访问**:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# 重启服务使配置生效
|
|
210
|
+
cc-gw restart --daemon
|
|
211
|
+
|
|
212
|
+
# 访问 HTTPS 端点
|
|
213
|
+
curl https://127.0.0.1:4443/health
|
|
214
|
+
|
|
215
|
+
# Web UI HTTPS 访问
|
|
216
|
+
open https://127.0.0.1:4443/ui
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**环境变量配置**:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# 推荐:使用 HTTP(默认)
|
|
223
|
+
export ANTHROPIC_BASE_URL=http://127.0.0.1:4100/anthropic
|
|
224
|
+
export OPENAI_BASE_URL=http://127.0.0.1:4100/openai/v1
|
|
225
|
+
|
|
226
|
+
# 如果使用 HTTPS(需要受信任的证书)
|
|
227
|
+
export ANTHROPIC_BASE_URL=https://127.0.0.1:4443/anthropic
|
|
228
|
+
export OPENAI_BASE_URL=https://127.0.0.1:4443/openai/v1
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**证书路径说明**:
|
|
232
|
+
- `keyPath`: 私钥文件路径(必需)
|
|
233
|
+
- `certPath`: 证书文件路径(必需)
|
|
234
|
+
- `caPath`: CA 证书路径(可选,用于证书链)
|
|
235
|
+
|
|
236
|
+
##### 6.4 自定义接入点(Custom Endpoints)
|
|
170
237
|
|
|
171
238
|
cc-gw 支持创建额外的自定义 API 端点,每个端点可以:
|
|
172
239
|
- 使用不同的协议(Anthropic、OpenAI)
|
|
@@ -220,6 +287,12 @@ cc-gw 支持创建额外的自定义 API 端点,每个端点可以:
|
|
|
220
287
|
- 检查模型路由配置
|
|
221
288
|
- 确认上游服务模型名称正确
|
|
222
289
|
|
|
290
|
+
4. **HTTPS 连接问题**:
|
|
291
|
+
- ⚠️ **Claude Code 无法连接**: 自签名证书会导致 "Unable to connect to API" 错误,建议使用 HTTP 协议(本地 127.0.0.1 访问安全)
|
|
292
|
+
- **证书路径错误**: 检查配置文件中的 `keyPath` 和 `certPath` 是否正确
|
|
293
|
+
- **需要受信任证书**: 如必须使用 HTTPS,请配置 Let's Encrypt 等受信任 CA 签发的证书
|
|
294
|
+
- **两个协议都禁用**: 至少要启用 HTTP 或 HTTPS 中的一个
|
|
295
|
+
|
|
223
296
|
> ✅ 完成以上 6 个步骤后,你的 cc-gw 网关就完全配置好了!所有 AI 客户端都可以通过统一的网关访问不同的模型服务。
|
|
224
297
|
|
|
225
298
|
### 推荐方式:npm 全局安装
|
|
@@ -305,6 +378,19 @@ UI 支持中英文、深色/浅色主题以及移动端响应式布局,提供
|
|
|
305
378
|
|
|
306
379
|
```json
|
|
307
380
|
{
|
|
381
|
+
"http": {
|
|
382
|
+
"enabled": true,
|
|
383
|
+
"port": 4100,
|
|
384
|
+
"host": "127.0.0.1"
|
|
385
|
+
},
|
|
386
|
+
"https": {
|
|
387
|
+
"enabled": true,
|
|
388
|
+
"port": 4443,
|
|
389
|
+
"host": "127.0.0.1",
|
|
390
|
+
"keyPath": "~/.cc-gw/certs/key.pem",
|
|
391
|
+
"certPath": "~/.cc-gw/certs/cert.pem",
|
|
392
|
+
"caPath": ""
|
|
393
|
+
},
|
|
308
394
|
"host": "127.0.0.1",
|
|
309
395
|
"port": 4100,
|
|
310
396
|
"providers": [
|
|
@@ -348,8 +434,15 @@ UI 支持中英文、深色/浅色主题以及移动端响应式布局,提供
|
|
|
348
434
|
}
|
|
349
435
|
```
|
|
350
436
|
|
|
351
|
-
字段要点(建议仍以 Web UI
|
|
437
|
+
字段要点(建议仍以 Web UI "系统设置 / 模型管理" 进行操作,下列仅便于理解结构):
|
|
352
438
|
|
|
439
|
+
- `http` / `https`:协议配置,支持独立启用/禁用,但至少要保持一个启用。
|
|
440
|
+
- `enabled`:是否启用该协议
|
|
441
|
+
- `port`:监听端口
|
|
442
|
+
- `host`:监听地址
|
|
443
|
+
- `keyPath` / `certPath`(仅 HTTPS):SSL/TLS 证书路径
|
|
444
|
+
- `caPath`(可选):CA 证书链路径
|
|
445
|
+
- `host` / `port`:旧格式向后兼容字段,新配置会自动迁移到 `http` / `https` 格式。
|
|
353
446
|
- `providers`:定义上游服务;`type` 支持 `openai | anthropic | kimi | deepseek | custom`。
|
|
354
447
|
- 模型标识使用 `providerId:modelId` 形式供路由引用。
|
|
355
448
|
- `modelRoutes`:将 Claude 发起的模型名映射到上游模型;支持在源模型名中使用 `*` 通配符匹配,匹配度更高(字符更多)的规则优先,同等情况下按配置顺序取第一条;若希望直接透传请求的模型名,可将目标写成 `providerId:*`,此时会将源请求中的模型名原样发送给对应 Provider。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chenpu17/cc-gw",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"better-sqlite3": "^12.4.1",
|
|
60
60
|
"colorette": "^2.0.20",
|
|
61
61
|
"commander": "^12.0.0",
|
|
62
|
-
"jszip": "^3.10.1",
|
|
63
62
|
"fastify": "^4.26.2",
|
|
63
|
+
"jszip": "^3.10.1",
|
|
64
64
|
"open": "^10.1.0",
|
|
65
65
|
"tiktoken": "^1.0.21",
|
|
66
66
|
"undici": "^6.11.1"
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@eslint/js": "^9.5.0",
|
|
70
70
|
"@playwright/test": "^1.55.1",
|
|
71
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
71
72
|
"@types/node": "^20.12.7",
|
|
72
73
|
"eslint": "^8.57.0",
|
|
73
74
|
"globals": "^15.0.0",
|
package/src/cli/dist/index.js
CHANGED
|
@@ -97,6 +97,20 @@ async function ensureConfigTemplate(port) {
|
|
|
97
97
|
longContextThreshold: 6e4
|
|
98
98
|
};
|
|
99
99
|
const template = {
|
|
100
|
+
http: {
|
|
101
|
+
enabled: true,
|
|
102
|
+
port: selectedPort,
|
|
103
|
+
host: "127.0.0.1"
|
|
104
|
+
},
|
|
105
|
+
https: {
|
|
106
|
+
enabled: false,
|
|
107
|
+
port: 4443,
|
|
108
|
+
host: "127.0.0.1",
|
|
109
|
+
keyPath: "",
|
|
110
|
+
certPath: "",
|
|
111
|
+
caPath: ""
|
|
112
|
+
},
|
|
113
|
+
// 保留旧字段以兼容
|
|
100
114
|
host: "127.0.0.1",
|
|
101
115
|
port: selectedPort,
|
|
102
116
|
providers: [],
|
|
@@ -218,10 +232,14 @@ async function handleStart(options) {
|
|
|
218
232
|
}
|
|
219
233
|
if (configCreated) {
|
|
220
234
|
console.log(green(`\u5DF2\u5728 ${CONFIG_FILE} \u751F\u6210\u9ED8\u8BA4\u914D\u7F6E`));
|
|
221
|
-
console.log(yellow(`\u9996\u6B21\u542F\u52A8\uFF1A\u5F85\u670D\u52A1\u5C31\u7EEA\u540E\uFF0C\u8BF7\
|
|
235
|
+
console.log(yellow(`\u9996\u6B21\u542F\u52A8\uFF1A\u5F85\u670D\u52A1\u5C31\u7EEA\u540E\uFF0C\u8BF7\u8BBF\u95EE\u4EE5\u4E0B\u5730\u5740\u8FDB\u884C\u914D\u7F6E:`));
|
|
236
|
+
console.log(yellow(` HTTP: http://127.0.0.1:${effectivePort}/ui`));
|
|
237
|
+
console.log(yellow(` HTTPS: https://127.0.0.1:4443/ui (\u9700\u5148\u751F\u6210\u8BC1\u4E66)`));
|
|
222
238
|
}
|
|
223
239
|
if (daemonMode) {
|
|
224
|
-
console.log(green(
|
|
240
|
+
console.log(green(`\u670D\u52A1\u5DF2\u542F\u52A8:`));
|
|
241
|
+
console.log(green(` HTTP: http://127.0.0.1:${effectivePort}/ui`));
|
|
242
|
+
console.log(green(` HTTPS: https://127.0.0.1:4443/ui (\u5982\u5DF2\u542F\u7528)`));
|
|
225
243
|
}
|
|
226
244
|
if (!daemonMode) {
|
|
227
245
|
const forwardSignal = (signal) => {
|
package/src/server/dist/index.js
CHANGED
|
@@ -9921,6 +9921,7 @@ var LOG_LEVELS = /* @__PURE__ */ new Set([
|
|
|
9921
9921
|
var HOME_OVERRIDE = process.env.CC_GW_HOME;
|
|
9922
9922
|
var HOME_DIR = path.resolve(HOME_OVERRIDE ?? path.join(os.homedir(), ".cc-gw"));
|
|
9923
9923
|
var CONFIG_PATH = path.join(HOME_DIR, "config.json");
|
|
9924
|
+
var CERTS_DIR = path.join(HOME_DIR, "certs");
|
|
9924
9925
|
var TypedEmitter = class extends EventEmitter {
|
|
9925
9926
|
on(event, listener) {
|
|
9926
9927
|
return super.on(event, listener);
|
|
@@ -9973,6 +9974,42 @@ function sanitizeModelRoutes(input) {
|
|
|
9973
9974
|
}
|
|
9974
9975
|
return sanitized;
|
|
9975
9976
|
}
|
|
9977
|
+
function migrateProtocolConfig(data) {
|
|
9978
|
+
if (data.http || data.https) {
|
|
9979
|
+
return;
|
|
9980
|
+
}
|
|
9981
|
+
const port = typeof data.port === "number" ? data.port : 4100;
|
|
9982
|
+
const host = typeof data.host === "string" ? data.host : "127.0.0.1";
|
|
9983
|
+
data.http = {
|
|
9984
|
+
enabled: true,
|
|
9985
|
+
port,
|
|
9986
|
+
host
|
|
9987
|
+
};
|
|
9988
|
+
const hasLegacyHttpsConfig = typeof data.httpsPort === "number" || typeof data.keyPath === "string" && data.keyPath || typeof data.certPath === "string" && data.certPath;
|
|
9989
|
+
data.https = {
|
|
9990
|
+
enabled: hasLegacyHttpsConfig ? true : false,
|
|
9991
|
+
port: typeof data.httpsPort === "number" ? data.httpsPort : 4443,
|
|
9992
|
+
host: typeof data.httpsHost === "string" ? data.httpsHost : host,
|
|
9993
|
+
keyPath: typeof data.keyPath === "string" ? data.keyPath : path.join(CERTS_DIR, "key.pem"),
|
|
9994
|
+
certPath: typeof data.certPath === "string" ? data.certPath : path.join(CERTS_DIR, "cert.pem"),
|
|
9995
|
+
caPath: typeof data.caPath === "string" ? data.caPath : ""
|
|
9996
|
+
};
|
|
9997
|
+
data.port = port;
|
|
9998
|
+
data.host = host;
|
|
9999
|
+
}
|
|
10000
|
+
function validateProtocolConfig(data) {
|
|
10001
|
+
const httpEnabled = data.http?.enabled === true;
|
|
10002
|
+
const httpsEnabled = data.https?.enabled === true;
|
|
10003
|
+
if (!httpEnabled && !httpsEnabled) {
|
|
10004
|
+
throw new Error("\u81F3\u5C11\u9700\u8981\u542F\u7528 HTTP \u6216 HTTPS \u534F\u8BAE");
|
|
10005
|
+
}
|
|
10006
|
+
if (httpsEnabled) {
|
|
10007
|
+
const https = data.https;
|
|
10008
|
+
if (!https.keyPath || !https.certPath) {
|
|
10009
|
+
throw new Error("HTTPS \u5DF2\u542F\u7528\u4F46\u7F3A\u5C11\u8BC1\u4E66\u8DEF\u5F84\u914D\u7F6E");
|
|
10010
|
+
}
|
|
10011
|
+
}
|
|
10012
|
+
}
|
|
9976
10013
|
function sanitizeWebAuth(input) {
|
|
9977
10014
|
if (!input || typeof input !== "object") {
|
|
9978
10015
|
return {
|
|
@@ -10021,8 +10058,10 @@ function resolveEndpointRouting(source, fallback) {
|
|
|
10021
10058
|
}
|
|
10022
10059
|
function parseConfig(raw) {
|
|
10023
10060
|
const data = JSON.parse(raw);
|
|
10061
|
+
migrateProtocolConfig(data);
|
|
10062
|
+
validateProtocolConfig(data);
|
|
10024
10063
|
if (typeof data.port !== "number") {
|
|
10025
|
-
|
|
10064
|
+
data.port = data.http?.port ?? 4100;
|
|
10026
10065
|
}
|
|
10027
10066
|
if (!Array.isArray(data.providers)) {
|
|
10028
10067
|
data.providers = [];
|
|
@@ -12132,8 +12171,8 @@ async function registerMessagesRoute(app) {
|
|
|
12132
12171
|
if (providerType === "anthropic") {
|
|
12133
12172
|
providerBody = cloneOriginalPayload(payload);
|
|
12134
12173
|
providerBody.model = target.modelId;
|
|
12135
|
-
if (
|
|
12136
|
-
providerBody.stream =
|
|
12174
|
+
if (Object.prototype.hasOwnProperty.call(payload, "stream")) {
|
|
12175
|
+
providerBody.stream = Boolean(payload.stream);
|
|
12137
12176
|
}
|
|
12138
12177
|
const collected = {};
|
|
12139
12178
|
const skip = /* @__PURE__ */ new Set(["content-length", "host", "connection", "transfer-encoding"]);
|
|
@@ -13806,7 +13845,9 @@ async function registerOpenAiRoutes(app) {
|
|
|
13806
13845
|
overrideTools: Array.isArray(payload.tools) ? payload.tools : void 0
|
|
13807
13846
|
});
|
|
13808
13847
|
providerBody.model = target.modelId;
|
|
13809
|
-
|
|
13848
|
+
if (Object.prototype.hasOwnProperty.call(payload, "stream")) {
|
|
13849
|
+
providerBody.stream = Boolean(payload.stream);
|
|
13850
|
+
}
|
|
13810
13851
|
const rawHeaders = request.raw?.headers ?? request.headers;
|
|
13811
13852
|
const forwarded = collectAnthropicForwardHeaders(rawHeaders);
|
|
13812
13853
|
providerHeaders = filterForwardedAnthropicHeaders(forwarded);
|
|
@@ -13845,7 +13886,9 @@ async function registerOpenAiRoutes(app) {
|
|
|
13845
13886
|
} else {
|
|
13846
13887
|
providerBody = { ...payload };
|
|
13847
13888
|
providerBody.model = target.modelId;
|
|
13848
|
-
|
|
13889
|
+
if (Object.prototype.hasOwnProperty.call(payload, "stream")) {
|
|
13890
|
+
providerBody.stream = Boolean(payload.stream);
|
|
13891
|
+
}
|
|
13849
13892
|
if (providerBody.max_output_tokens == null && typeof providerBody.max_tokens === "number") {
|
|
13850
13893
|
providerBody.max_output_tokens = providerBody.max_tokens;
|
|
13851
13894
|
}
|
|
@@ -14371,8 +14414,8 @@ async function registerOpenAiRoutes(app) {
|
|
|
14371
14414
|
inputTokens: finalPromptTokens,
|
|
14372
14415
|
outputTokens: finalCompletionTokens,
|
|
14373
14416
|
cachedTokens: finalCachedTokens ?? null,
|
|
14374
|
-
cacheReadTokens:
|
|
14375
|
-
cacheCreationTokens:
|
|
14417
|
+
cacheReadTokens: finalCachedResult.read,
|
|
14418
|
+
cacheCreationTokens: finalCachedResult.creation,
|
|
14376
14419
|
ttftMs,
|
|
14377
14420
|
tpotMs: computeTpot2(totalLatencyMs, finalCompletionTokens, {
|
|
14378
14421
|
streaming: true,
|
|
@@ -14538,12 +14581,16 @@ async function registerOpenAiRoutes(app) {
|
|
|
14538
14581
|
const textOutputTokens = usageCompletion ?? 0;
|
|
14539
14582
|
const reasoningTokens = usageReasoning ?? 0;
|
|
14540
14583
|
const outputTokens = textOutputTokens + reasoningTokens;
|
|
14584
|
+
const hasCacheStats = usageCached != null;
|
|
14585
|
+
const resolvedCachedTokens = hasCacheStats ? usageCached : null;
|
|
14586
|
+
const resolvedCacheRead = hasCacheStats ? usageCacheRead : null;
|
|
14587
|
+
const resolvedCacheCreation = hasCacheStats ? usageCacheCreation : null;
|
|
14541
14588
|
await updateLogTokens(logId, {
|
|
14542
14589
|
inputTokens,
|
|
14543
14590
|
outputTokens,
|
|
14544
|
-
cachedTokens:
|
|
14545
|
-
cacheReadTokens:
|
|
14546
|
-
cacheCreationTokens:
|
|
14591
|
+
cachedTokens: resolvedCachedTokens,
|
|
14592
|
+
cacheReadTokens: resolvedCacheRead,
|
|
14593
|
+
cacheCreationTokens: resolvedCacheCreation,
|
|
14547
14594
|
ttftMs: firstTokenAt ? firstTokenAt - requestStart : null,
|
|
14548
14595
|
tpotMs: computeTpot2(latencyMs, outputTokens, {
|
|
14549
14596
|
streaming: true,
|
|
@@ -14556,6 +14603,9 @@ async function registerOpenAiRoutes(app) {
|
|
|
14556
14603
|
requests: 1,
|
|
14557
14604
|
inputTokens,
|
|
14558
14605
|
outputTokens,
|
|
14606
|
+
cachedTokens: resolvedCachedTokens ?? 0,
|
|
14607
|
+
cacheReadTokens: resolvedCacheRead ?? 0,
|
|
14608
|
+
cacheCreationTokens: resolvedCacheCreation ?? 0,
|
|
14559
14609
|
latencyMs
|
|
14560
14610
|
});
|
|
14561
14611
|
await finalize(200, null);
|
|
@@ -14687,7 +14737,9 @@ async function registerOpenAiRoutes(app) {
|
|
|
14687
14737
|
overrideTools
|
|
14688
14738
|
});
|
|
14689
14739
|
providerBody.model = target.modelId;
|
|
14690
|
-
|
|
14740
|
+
if (Object.prototype.hasOwnProperty.call(payload, "stream")) {
|
|
14741
|
+
providerBody.stream = Boolean(payload.stream);
|
|
14742
|
+
}
|
|
14691
14743
|
const rawHeaders = request.raw?.headers ?? request.headers;
|
|
14692
14744
|
const forwarded = collectAnthropicForwardHeaders(rawHeaders);
|
|
14693
14745
|
providerHeaders = filterForwardedAnthropicHeaders(forwarded);
|
|
@@ -14731,7 +14783,9 @@ async function registerOpenAiRoutes(app) {
|
|
|
14731
14783
|
overrideTools
|
|
14732
14784
|
});
|
|
14733
14785
|
providerBody.model = target.modelId;
|
|
14734
|
-
|
|
14786
|
+
if (Object.prototype.hasOwnProperty.call(payload, "stream")) {
|
|
14787
|
+
providerBody.stream = Boolean(payload.stream);
|
|
14788
|
+
}
|
|
14735
14789
|
if (Array.isArray(payload.functions) && !providerBody.functions) {
|
|
14736
14790
|
providerBody.functions = payload.functions;
|
|
14737
14791
|
}
|
|
@@ -14807,7 +14861,7 @@ async function registerOpenAiRoutes(app) {
|
|
|
14807
14861
|
await updateLogTokens(logId, {
|
|
14808
14862
|
inputTokens: inputTokens3,
|
|
14809
14863
|
outputTokens: outputTokens3,
|
|
14810
|
-
cachedTokens:
|
|
14864
|
+
cachedTokens: cachedTokens3,
|
|
14811
14865
|
cacheReadTokens: cached3.read,
|
|
14812
14866
|
cacheCreationTokens: cached3.creation,
|
|
14813
14867
|
ttftMs: latencyMs3,
|
|
@@ -14818,9 +14872,9 @@ async function registerOpenAiRoutes(app) {
|
|
|
14818
14872
|
requests: 1,
|
|
14819
14873
|
inputTokens: inputTokens3,
|
|
14820
14874
|
outputTokens: outputTokens3,
|
|
14821
|
-
cachedTokens:
|
|
14822
|
-
cacheReadTokens:
|
|
14823
|
-
cacheCreationTokens:
|
|
14875
|
+
cachedTokens: cachedTokens3,
|
|
14876
|
+
cacheReadTokens: cached3.read,
|
|
14877
|
+
cacheCreationTokens: cached3.creation,
|
|
14824
14878
|
latencyMs: latencyMs3
|
|
14825
14879
|
});
|
|
14826
14880
|
if (storeResponsePayloads) {
|
|
@@ -14856,7 +14910,7 @@ async function registerOpenAiRoutes(app) {
|
|
|
14856
14910
|
await updateLogTokens(logId, {
|
|
14857
14911
|
inputTokens: inputTokens2,
|
|
14858
14912
|
outputTokens: outputTokens2,
|
|
14859
|
-
cachedTokens:
|
|
14913
|
+
cachedTokens: cachedTokens2,
|
|
14860
14914
|
cacheReadTokens: cached2.read,
|
|
14861
14915
|
cacheCreationTokens: cached2.creation,
|
|
14862
14916
|
ttftMs: usagePayload?.first_token_latency_ms ?? latencyMs2,
|
|
@@ -15294,8 +15348,8 @@ async function registerOpenAiRoutes(app) {
|
|
|
15294
15348
|
inputTokens: finalPromptTokens,
|
|
15295
15349
|
outputTokens: finalCompletionTokens,
|
|
15296
15350
|
cachedTokens: finalCachedTokens ?? null,
|
|
15297
|
-
cacheReadTokens:
|
|
15298
|
-
cacheCreationTokens:
|
|
15351
|
+
cacheReadTokens: finalCachedResult.read,
|
|
15352
|
+
cacheCreationTokens: finalCachedResult.creation,
|
|
15299
15353
|
ttftMs,
|
|
15300
15354
|
tpotMs: computeTpot2(totalLatencyMs, finalCompletionTokens, {
|
|
15301
15355
|
streaming: true,
|
|
@@ -15436,12 +15490,16 @@ async function registerOpenAiRoutes(app) {
|
|
|
15436
15490
|
const latencyMs = Date.now() - requestStart;
|
|
15437
15491
|
const inputTokens = usagePrompt ?? usageCompletion ?? target.tokenEstimate ?? estimateTokens(normalized, target.modelId);
|
|
15438
15492
|
const outputTokens = usageCompletion ?? 0;
|
|
15493
|
+
const hasCacheStats = usageCached != null;
|
|
15494
|
+
const resolvedCachedTokens = hasCacheStats ? usageCached : null;
|
|
15495
|
+
const resolvedCacheRead = hasCacheStats ? usageCacheRead : null;
|
|
15496
|
+
const resolvedCacheCreation = hasCacheStats ? usageCacheCreation : null;
|
|
15439
15497
|
await updateLogTokens(logId, {
|
|
15440
15498
|
inputTokens,
|
|
15441
15499
|
outputTokens,
|
|
15442
|
-
cachedTokens:
|
|
15443
|
-
cacheReadTokens:
|
|
15444
|
-
cacheCreationTokens:
|
|
15500
|
+
cachedTokens: resolvedCachedTokens,
|
|
15501
|
+
cacheReadTokens: resolvedCacheRead,
|
|
15502
|
+
cacheCreationTokens: resolvedCacheCreation,
|
|
15445
15503
|
ttftMs: firstTokenAt ? firstTokenAt - requestStart : null,
|
|
15446
15504
|
tpotMs: computeTpot2(latencyMs, outputTokens, {
|
|
15447
15505
|
streaming: true,
|
|
@@ -15453,6 +15511,9 @@ async function registerOpenAiRoutes(app) {
|
|
|
15453
15511
|
requests: 1,
|
|
15454
15512
|
inputTokens,
|
|
15455
15513
|
outputTokens,
|
|
15514
|
+
cachedTokens: resolvedCachedTokens ?? 0,
|
|
15515
|
+
cacheReadTokens: resolvedCacheRead ?? 0,
|
|
15516
|
+
cacheCreationTokens: resolvedCacheCreation ?? 0,
|
|
15456
15517
|
latencyMs
|
|
15457
15518
|
});
|
|
15458
15519
|
await finalize(200, null);
|
|
@@ -17544,8 +17605,8 @@ async function handleAnthropicProtocol(request, reply, endpoint, endpointId, app
|
|
|
17544
17605
|
if (providerType === "anthropic") {
|
|
17545
17606
|
providerBody = cloneOriginalPayload2(payload);
|
|
17546
17607
|
providerBody.model = target.modelId;
|
|
17547
|
-
if (
|
|
17548
|
-
providerBody.stream =
|
|
17608
|
+
if (Object.prototype.hasOwnProperty.call(payload, "stream")) {
|
|
17609
|
+
providerBody.stream = Boolean(payload.stream);
|
|
17549
17610
|
}
|
|
17550
17611
|
const collected = {};
|
|
17551
17612
|
const skip = /* @__PURE__ */ new Set(["content-length", "host", "connection", "transfer-encoding"]);
|
|
@@ -17874,7 +17935,9 @@ async function handleOpenAIChatProtocol(request, reply, endpoint, endpointId, ap
|
|
|
17874
17935
|
});
|
|
17875
17936
|
}
|
|
17876
17937
|
providerBody.model = target.modelId;
|
|
17877
|
-
|
|
17938
|
+
if (Object.prototype.hasOwnProperty.call(payload, "stream")) {
|
|
17939
|
+
providerBody.stream = Boolean(payload.stream);
|
|
17940
|
+
}
|
|
17878
17941
|
const upstream = await connector.send({
|
|
17879
17942
|
model: target.modelId,
|
|
17880
17943
|
body: providerBody,
|
|
@@ -18165,7 +18228,9 @@ async function handleOpenAIResponsesProtocol(request, reply, endpoint, endpointI
|
|
|
18165
18228
|
});
|
|
18166
18229
|
}
|
|
18167
18230
|
providerBody.model = target.modelId;
|
|
18168
|
-
|
|
18231
|
+
if (Object.prototype.hasOwnProperty.call(payload, "stream")) {
|
|
18232
|
+
providerBody.stream = Boolean(payload.stream);
|
|
18233
|
+
}
|
|
18169
18234
|
const upstream = await connector.send({
|
|
18170
18235
|
model: target.modelId,
|
|
18171
18236
|
body: providerBody,
|
|
@@ -18196,7 +18261,7 @@ async function handleOpenAIResponsesProtocol(request, reply, endpoint, endpointI
|
|
|
18196
18261
|
await updateLogTokens(logId, {
|
|
18197
18262
|
inputTokens: inputTokens2,
|
|
18198
18263
|
outputTokens: outputTokens2,
|
|
18199
|
-
cachedTokens:
|
|
18264
|
+
cachedTokens: cachedTokens2,
|
|
18200
18265
|
cacheReadTokens: cached2.read,
|
|
18201
18266
|
cacheCreationTokens: cached2.creation,
|
|
18202
18267
|
ttftMs: latencyMs2,
|
|
@@ -18339,11 +18404,11 @@ function startMaintenanceTimers() {
|
|
|
18339
18404
|
scheduleCleanup();
|
|
18340
18405
|
}
|
|
18341
18406
|
function scheduleCleanup() {
|
|
18342
|
-
const run2 = () => {
|
|
18407
|
+
const run2 = async () => {
|
|
18343
18408
|
try {
|
|
18344
18409
|
const retentionDays = getConfig().logRetentionDays ?? 30;
|
|
18345
18410
|
const cutoff = Date.now() - retentionDays * DAY_MS;
|
|
18346
|
-
const deleted = cleanupLogsBefore(cutoff);
|
|
18411
|
+
const deleted = await cleanupLogsBefore(cutoff);
|
|
18347
18412
|
if (deleted > 0) {
|
|
18348
18413
|
console.info(`[maintenance] cleaned ${deleted} old log entries`);
|
|
18349
18414
|
}
|
|
@@ -18474,17 +18539,30 @@ async function syncCustomEndpoints(app, config) {
|
|
|
18474
18539
|
);
|
|
18475
18540
|
}
|
|
18476
18541
|
}
|
|
18477
|
-
async function createServer() {
|
|
18542
|
+
async function createServer(protocol = "http") {
|
|
18478
18543
|
const config = cachedConfig2 ?? loadConfig();
|
|
18479
18544
|
const requestLogEnabled = config.requestLogging !== false;
|
|
18480
18545
|
const responseLogEnabled = config.responseLogging !== false;
|
|
18481
18546
|
const bodyLimit = typeof config.bodyLimit === "number" && Number.isFinite(config.bodyLimit) && config.bodyLimit > 0 ? config.bodyLimit : 10 * 1024 * 1024;
|
|
18547
|
+
let httpsOptions;
|
|
18548
|
+
if (protocol === "https" && config.https?.enabled) {
|
|
18549
|
+
const { keyPath, certPath, caPath } = config.https;
|
|
18550
|
+
if (!fs4.existsSync(keyPath) || !fs4.existsSync(certPath)) {
|
|
18551
|
+
throw new Error(`HTTPS \u8BC1\u4E66\u6587\u4EF6\u4E0D\u5B58\u5728: ${keyPath}, ${certPath}`);
|
|
18552
|
+
}
|
|
18553
|
+
httpsOptions = {
|
|
18554
|
+
key: fs4.readFileSync(keyPath),
|
|
18555
|
+
cert: fs4.readFileSync(certPath),
|
|
18556
|
+
ca: caPath ? fs4.readFileSync(caPath) : void 0
|
|
18557
|
+
};
|
|
18558
|
+
}
|
|
18482
18559
|
const app = Fastify({
|
|
18483
18560
|
logger: {
|
|
18484
18561
|
level: config.logLevel ?? "info"
|
|
18485
18562
|
},
|
|
18486
18563
|
disableRequestLogging: true,
|
|
18487
|
-
bodyLimit
|
|
18564
|
+
bodyLimit,
|
|
18565
|
+
https: httpsOptions
|
|
18488
18566
|
});
|
|
18489
18567
|
app.addHook("onRequest", async (request, reply) => {
|
|
18490
18568
|
const authConfig = (cachedConfig2 ?? getConfig()).webAuth;
|
|
@@ -18625,25 +18703,54 @@ async function createServer() {
|
|
|
18625
18703
|
return app;
|
|
18626
18704
|
}
|
|
18627
18705
|
async function startServer(options = {}) {
|
|
18628
|
-
const
|
|
18629
|
-
const
|
|
18630
|
-
|
|
18631
|
-
|
|
18632
|
-
|
|
18633
|
-
|
|
18634
|
-
|
|
18635
|
-
|
|
18636
|
-
|
|
18706
|
+
const config = cachedConfig2 ?? loadConfig();
|
|
18707
|
+
const result = {};
|
|
18708
|
+
if (config.http?.enabled !== false) {
|
|
18709
|
+
const httpApp = await createServer("http");
|
|
18710
|
+
const httpPort = options.port ?? (process2.env.PORT ? Number.parseInt(process2.env.PORT, 10) : config.http?.port ?? config.port ?? DEFAULT_PORT);
|
|
18711
|
+
const httpHost = options.host ?? process2.env.HOST ?? config.http?.host ?? config.host ?? DEFAULT_HOST;
|
|
18712
|
+
await httpApp.listen({ port: httpPort, host: httpHost });
|
|
18713
|
+
httpApp.log.info(`HTTP server started at http://${httpHost}:${httpPort}`);
|
|
18714
|
+
result.http = httpApp;
|
|
18715
|
+
}
|
|
18716
|
+
if (config.https?.enabled === true) {
|
|
18717
|
+
try {
|
|
18718
|
+
const httpsApp = await createServer("https");
|
|
18719
|
+
const httpsPort = config.https.port;
|
|
18720
|
+
const httpsHost = config.https.host ?? config.host ?? DEFAULT_HOST;
|
|
18721
|
+
await httpsApp.listen({ port: httpsPort, host: httpsHost });
|
|
18722
|
+
httpsApp.log.info(`HTTPS server started at https://${httpsHost}:${httpsPort}`);
|
|
18723
|
+
result.https = httpsApp;
|
|
18724
|
+
} catch (error) {
|
|
18725
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
18726
|
+
console.error(`HTTPS server\u542F\u52A8\u5931\u8D25: ${errorMessage}`);
|
|
18727
|
+
if (!result.http) {
|
|
18728
|
+
throw error;
|
|
18729
|
+
}
|
|
18730
|
+
console.warn("\u4EC5 HTTP \u670D\u52A1\u5668\u542F\u52A8\u6210\u529F,HTTPS \u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25");
|
|
18731
|
+
}
|
|
18732
|
+
}
|
|
18733
|
+
if (!result.http && !result.https) {
|
|
18734
|
+
throw new Error("HTTP \u548C HTTPS \u670D\u52A1\u5668\u5747\u672A\u542F\u52A8");
|
|
18735
|
+
}
|
|
18736
|
+
return result;
|
|
18637
18737
|
}
|
|
18638
18738
|
async function main() {
|
|
18639
18739
|
try {
|
|
18640
|
-
const
|
|
18740
|
+
const servers = await startServer();
|
|
18641
18741
|
const shutdown = async () => {
|
|
18642
18742
|
try {
|
|
18643
|
-
|
|
18743
|
+
const closePromises = [];
|
|
18744
|
+
if (servers.http) {
|
|
18745
|
+
closePromises.push(servers.http.close());
|
|
18746
|
+
}
|
|
18747
|
+
if (servers.https) {
|
|
18748
|
+
closePromises.push(servers.https.close());
|
|
18749
|
+
}
|
|
18750
|
+
await Promise.all(closePromises);
|
|
18644
18751
|
process2.exit(0);
|
|
18645
18752
|
} catch (err) {
|
|
18646
|
-
|
|
18753
|
+
console.error("\u5173\u95ED\u670D\u52A1\u5931\u8D25:", err);
|
|
18647
18754
|
process2.exit(1);
|
|
18648
18755
|
}
|
|
18649
18756
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as p,u as v,a as k,r,j as e,d as o,U as j,m as i}from"./index-
|
|
1
|
+
import{c as p,u as v,a as k,r,j as e,d as o,U as j,m as i}from"./index-DP6DzFEd.js";import{u as N}from"./useApiQuery-C5jmZPyb.js";import{P as w,a as d}from"./PageSection-Bq4tdag3.js";import"./Input-B6cOxhbI.js";import{B as b}from"./Button-BkhovQFd.js";import{I as y}from"./info-CADQNr0Q.js";/**
|
|
2
2
|
* @license lucide-react v0.344.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -8,4 +8,4 @@ import{c as p,u as v,a as k,r,j as e,d as o,U as j,m as i}from"./index-3UByifOG.
|
|
|
8
8
|
*
|
|
9
9
|
* This source code is licensed under the ISC license.
|
|
10
10
|
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
-
*/const E=p("Sparkles",[["path",{d:"m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z",key:"17u4zn"}],["path",{d:"M5 3v4",key:"bklmnn"}],["path",{d:"M19 17v4",key:"iiml17"}],["path",{d:"M3 5h4",key:"nem4j1"}],["path",{d:"M17 19h4",key:"lbex7p"}]]),I="0.5.
|
|
11
|
+
*/const E=p("Sparkles",[["path",{d:"m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z",key:"17u4zn"}],["path",{d:"M5 3v4",key:"bklmnn"}],["path",{d:"M19 17v4",key:"iiml17"}],["path",{d:"M3 5h4",key:"nem4j1"}],["path",{d:"M17 19h4",key:"lbex7p"}]]),I="0.5.2",_={version:I},L={VITE_BUILD_TIME:"2025-11-02T02:16:57.696Z",VITE_NODE_VERSION:"v22.16.0"};function m({items:t}){return t.length===0?null:e.jsx("dl",{className:"grid gap-4 sm:grid-cols-2 xl:grid-cols-2",children:t.map(s=>e.jsxs("div",{className:"rounded-2xl border border-slate-200/50 bg-white p-4 shadow-sm shadow-slate-200/30 transition-all duration-200 hover:-translate-y-0.5 hover:border-slate-200/70 hover:shadow-md hover:shadow-slate-200/40 dark:border-slate-700/50 dark:bg-slate-900/80 dark:shadow-lg dark:shadow-slate-900/30 dark:hover:border-slate-600/70",children:[e.jsx("dt",{className:"text-xs font-semibold uppercase tracking-[0.14em] text-slate-500 dark:text-slate-400",children:s.label}),e.jsx("dd",{className:"mt-2 text-base font-semibold text-slate-900 dark:text-slate-100",children:s.value}),s.hint?e.jsx("p",{className:o(i,"mt-2 text-xs leading-relaxed"),children:s.hint}):null]},s.label))})}function P(){const{t}=v(),{pushToast:s}=k(),a=N(["status","gateway"],{url:"/api/status",method:"GET"},{staleTime:6e4});r.useEffect(()=>{a.isError&&a.error&&s({title:t("about.toast.statusError.title"),description:a.error.message,variant:"error"})},[a.isError,a.error,s,t]);const n=_.version,l=r.useMemo(()=>{const u=L,f=u.VITE_BUILD_TIME,g=u.VITE_NODE_VERSION;return{buildTime:f,nodeVersion:g}},[]),h=r.useMemo(()=>[{label:t("about.app.labels.name"),value:e.jsx("span",{className:"font-mono text-sm font-semibold text-slate-900 dark:text-slate-100",children:"cc-gw"})},{label:t("about.app.labels.version"),value:e.jsxs("span",{className:"font-mono text-sm font-semibold text-blue-700 dark:text-blue-200",children:["v",n]})},{label:t("about.app.labels.buildTime"),value:l.buildTime,hint:t("about.app.hint.buildTime")},{label:t("about.app.labels.node"),value:e.jsx("span",{className:"font-mono text-sm text-slate-800 dark:text-slate-200",children:l.nodeVersion})}],[n,l.buildTime,l.nodeVersion,t]),c=r.useMemo(()=>a.data?[{label:t("about.status.labels.host"),value:a.data.host??"127.0.0.1"},{label:t("about.status.labels.port"),value:a.data.port.toLocaleString()},{label:t("about.status.labels.providers"),value:a.data.providers.toLocaleString()},{label:t("about.status.labels.active"),value:(a.data.activeRequests??0).toLocaleString(),hint:t("about.status.hint.active")}]:[],[a.data,t]),x=()=>{s({title:t("about.toast.updatesPlanned"),variant:"info"})};return e.jsxs("div",{className:"space-y-8",children:[e.jsx(w,{icon:e.jsx(y,{className:"h-6 w-6","aria-hidden":"true"}),title:t("about.title"),description:t("about.description"),badge:`v${n}`,actions:e.jsx(b,{variant:"primary",icon:e.jsx(E,{className:"h-4 w-4","aria-hidden":"true"}),onClick:x,children:t("about.support.actions.checkUpdates")})}),e.jsxs("div",{className:"grid gap-6 lg:grid-cols-2",children:[e.jsx(d,{title:t("about.app.title"),description:t("about.app.subtitle"),className:"h-full",contentClassName:"gap-4",children:e.jsx(m,{items:h})}),e.jsx(d,{title:t("about.status.title"),description:t("about.status.subtitle"),className:"h-full",contentClassName:"gap-4",actions:e.jsx(b,{variant:"subtle",size:"sm",icon:e.jsx(T,{className:"h-4 w-4","aria-hidden":"true"}),onClick:()=>a.refetch(),loading:a.isFetching,children:a.isFetching?t("common.actions.refreshing"):t("common.actions.refresh")}),children:a.isLoading?e.jsxs("div",{className:"flex h-36 flex-col items-center justify-center gap-3 text-center",children:[e.jsx("div",{className:"h-10 w-10 animate-spin rounded-full border-[3px] border-blue-500/30 border-t-blue-600 dark:border-blue-400/20 dark:border-t-blue-300"}),e.jsx("p",{className:o(i,"text-sm"),children:t("about.status.loading")})]}):c.length>0?e.jsx(m,{items:c}):e.jsxs("div",{className:"flex h-36 flex-col items-center justify-center gap-2 rounded-2xl border border-dashed border-slate-200/60 bg-white p-6 text-center shadow-inner dark:border-slate-700/60 dark:bg-slate-900/60",children:[e.jsx("p",{className:"text-sm font-semibold text-slate-700 dark:text-slate-200",children:t("about.status.empty")}),e.jsx("p",{className:o(i,"text-xs"),children:t("common.actions.refresh")})]})})]}),e.jsx(d,{title:t("about.support.title"),description:e.jsxs("span",{className:"space-y-1",children:[e.jsx("span",{className:"block text-sm font-semibold text-blue-600 dark:text-blue-300",children:t("about.support.subtitle")}),e.jsx("span",{children:t("about.support.description")})]}),className:"relative overflow-hidden",contentClassName:"gap-6",children:e.jsxs("div",{className:"flex flex-col gap-4 rounded-3xl border border-slate-200/50 bg-white p-6 shadow-lg shadow-slate-200/30 backdrop-blur-md dark:border-slate-700/50 dark:bg-slate-900/80 dark:shadow-slate-900/40",children:[e.jsxs("div",{className:"flex flex-wrap items-start gap-4",children:[e.jsx("div",{className:"grid h-12 w-12 place-items-center rounded-2xl bg-gradient-to-br from-blue-500/20 to-indigo-500/20 text-blue-600 shadow-inner dark:text-blue-200",children:e.jsx(j,{className:"h-6 w-6","aria-hidden":"true"})}),e.jsx("p",{className:o(i,"text-sm leading-6"),children:t("about.support.tip")})]}),e.jsx("code",{className:"inline-flex items-center gap-2 self-start rounded-full border border-blue-200/50 bg-blue-50/80 px-4 py-2 text-xs font-semibold tracking-wide text-blue-700 shadow-sm dark:border-blue-500/30 dark:bg-blue-900/30 dark:text-blue-200",children:"~/.cc-gw/config.json"})]})})]})}export{P as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as T,u as W,a as J,r as d,j as e,L as X,N as Y,d as t,b as K,m as r,H as m,E as Z,k as ee,l as ae,f as se,h as te}from"./index-
|
|
1
|
+
import{c as T,u as W,a as J,r as d,j as e,L as X,N as Y,d as t,b as K,m as r,H as m,E as Z,k as ee,l as ae,f as se,h as te}from"./index-DP6DzFEd.js";import{E as le}from"./index-BLBh7aj6.js";import{u as w}from"./useApiQuery-C5jmZPyb.js";import{P as ie,a as q}from"./PageSection-Bq4tdag3.js";import{F as I}from"./FormField-C-bAE13W.js";import{I as re}from"./Input-B6cOxhbI.js";import{B as C}from"./Button-BkhovQFd.js";import{S as ne}from"./StatusBadge-P00M_NBZ.js";import{C as ce}from"./copy-D321KBhI.js";/**
|
|
2
2
|
* @license lucide-react v0.344.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as s,d as c,J as i,E as p,k as b}from"./index-
|
|
1
|
+
import{j as s,d as c,J as i,E as p,k as b}from"./index-DP6DzFEd.js";function h({variant:n="subtle",size:o="md",children:a,loading:t,icon:e,className:l,disabled:r,...u}){const m={subtle:b,primary:p,danger:i}[n],x={sm:"h-8 px-3 text-xs",md:"h-10 px-4 text-sm",lg:"h-12 px-6 text-base"}[o];return s.jsx("button",{className:c(m,x,t&&"cursor-wait opacity-70",r&&"cursor-not-allowed opacity-50",l),disabled:r||t,...u,children:t?s.jsx("div",{className:"inline-block animate-spin rounded-full h-4 w-4 border-b-2 border-current"}):e?s.jsxs(s.Fragment,{children:[e,a]}):a})}export{h as B};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as O,u as q,a as te,r as h,b as se,t as ae,j as e,L as re,B,d as o,m as g,g as z,e as $,f as G,h as oe,l as _,s as le,i as M,k as ie,n as P}from"./index-
|
|
1
|
+
import{c as O,u as q,a as te,r as h,b as se,t as ae,j as e,L as re,B,d as o,m as g,g as z,e as $,f as G,h as oe,l as _,s as le,i as M,k as ie,n as P}from"./index-DP6DzFEd.js";import{E as ne}from"./index-BLBh7aj6.js";import{P as de,a as H}from"./PageSection-Bq4tdag3.js";import{S as ce}from"./Input-B6cOxhbI.js";import{S as me}from"./StatusBadge-P00M_NBZ.js";import{u as C}from"./useApiQuery-C5jmZPyb.js";/**
|
|
2
2
|
* @license lucide-react v0.344.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as s,d,P as m,Q as x}from"./index-
|
|
1
|
+
import{j as s,d,P as m,Q as x}from"./index-DP6DzFEd.js";function i({label:a,children:l,className:t,required:r,error:e}){return s.jsxs("div",{className:d(x,t),children:[s.jsxs("label",{className:m,children:[a,r&&s.jsx("span",{className:"text-red-500 ml-1",children:"*"})]}),l,e&&s.jsx("p",{className:"text-xs text-red-600 dark:text-red-400 mt-1",children:e})]})}export{i as F};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as u,u as p,r as b,j as e,d as x,m}from"./index-
|
|
1
|
+
import{c as u,u as p,r as b,j as e,d as x,m}from"./index-DP6DzFEd.js";import{P as g,a as o}from"./PageSection-Bq4tdag3.js";import{I as j}from"./info-CADQNr0Q.js";/**
|
|
2
2
|
* @license lucide-react v0.344.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as d,j as e,d as n,M as c,K as i}from"./index-
|
|
1
|
+
import{r as d,j as e,d as n,M as c,K as i}from"./index-DP6DzFEd.js";const f=d.forwardRef(({options:t,placeholder:s,className:r,...l},u)=>e.jsxs("select",{ref:u,className:n(c,r),...l,children:[s&&e.jsx("option",{value:"",disabled:!0,children:s}),t.map(a=>e.jsx("option",{value:a.value,disabled:a.disabled,children:a.label},a.value))]})),j=d.forwardRef(({variant:t="default",className:s,...r},l)=>e.jsx("input",{ref:l,className:n(i,s),...r}));export{j as I,f as S};
|