Full internal rename: metapi → boosapi

Rename all remaining internal protocol identifiers:
- x-metapi-* headers → x-boosapi-*
- metapi: reasoning prefix → boosapi:
- __metapi* runtime markers → __boosapi*
- file-metapi-* → file-boosapi-*
- METAPI_* env vars → BOOSAPI_*
- metapi_turn_state/metapi_mcp_item__ etc. → boosapi_*
- package.json name → boosapi
- Docker/deploy/k3s/docs references

46 files changed, 168 insertions, 170 deletions.
typecheck:web passes (0 new errors).

Signed-off-by: Boos4721 <boos4721@icloud.com>
This commit is contained in:
boos
2026-05-16 00:46:28 +08:00
parent d2c16c3919
commit 0106dd3f5d
46 changed files with 168 additions and 170 deletions
+2 -2
View File
@@ -25,7 +25,7 @@ Metapi 是 AI API 聚合平台(New API、One API、OneHub 等)的元聚合
```bash
git clone https://github.com/YOUR_USERNAME/metapi.git
cd metapi
cd boosapi
```
2. **Install dependencies** / **安装依赖**
@@ -213,7 +213,7 @@ If you're adding support for a new AI API platform / 如果您要添加对新 AI
## Getting Help / 获取帮助
- 📖 [Documentation](https://metapi.cita777.me) / [文档](https://metapi.cita777.me)
- 📖 [Documentation](https://boosapi.cita777.me) / [文档](https://boosapi.cita777.me)
- 💬 [GitHub Discussions](https://github.com/cita-777/metapi/discussions) / [GitHub 讨论区](https://github.com/cita-777/metapi/discussions)
- 🐛 [Issue Tracker](https://github.com/cita-777/metapi/issues) / [Issue 跟踪](https://github.com/cita-777/metapi/issues)
+13 -13
View File
@@ -37,8 +37,8 @@ RUN python3 -m venv venv \
ENV PATH="/app/comfy/venv/bin:${PATH}"
# ========== Metapi ==========
FROM base AS metapi
WORKDIR /app/metapi
FROM base AS boosapi
WORKDIR /app/boosapi
COPY . .
RUN npm install
RUN npm run build --if-present
@@ -56,15 +56,15 @@ RUN apt-get update && apt-get install -y \
COPY --from=rtk-builder /usr/local/bin/rtk /usr/local/bin/rtk
COPY --from=comfyui /app/comfy /app/comfy
COPY --from=comfyui /app/comfy/venv /app/comfy/venv
COPY --from=metapi /app/metapi /app/metapi
COPY --from=metapi /usr/lib/node_modules /usr/lib/node_modules
COPY --from=boosapi /app/boosapi /app/boosapi
COPY --from=boosapi /usr/lib/node_modules /usr/lib/node_modules
# Node path
ENV PATH="/app/comfy/venv/bin:/usr/local/bin:${PATH}"
ENV COMFYUI_BASE=http://127.0.0.1:8188
ENV AUTH_TOKEN=change-me-admin-token
WORKDIR /app/metapi
WORKDIR /app/boosapi
# Supervisor config
RUN mkdir -p /var/log/supervisor
@@ -75,19 +75,19 @@ user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/tmp/supervisord.pid
[program:metapi-server]
[program:boosapi-server]
command=npm run dev:server
directory=/app/metapi
directory=/app/boosapi
autorestart=true
stdout_logfile=/var/log/supervisor/metapi-server.log
stderr_logfile=/var/log/supervisor/metapi-server.err
stdout_logfile=/var/log/supervisor/boosapi-server.log
stderr_logfile=/var/log/supervisor/boosapi-server.err
[program:metapi-web]
[program:boosapi-web]
command=npx vite --host 0.0.0.0 --port 5173
directory=/app/metapi
directory=/app/boosapi
autorestart=true
stdout_logfile=/var/log/supervisor/metapi-web.log
stderr_logfile=/var/log/supervisor/metapi-web.err
stdout_logfile=/var/log/supervisor/boosapi-web.log
stderr_logfile=/var/log/supervisor/boosapi-web.err
[program:comfyui]
command=python3 main.py --listen 0.0.0.0 --port 8188
+1 -1
View File
@@ -158,7 +158,7 @@ mkdir boosapi && cd boosapi
cat > docker-compose.yml << 'EOF'
services:
boosapi:
image: 1467078763/metapi:latest
image: 1467078763/boosapi:latest
ports:
- "4000:4000"
volumes:
+1 -1
View File
@@ -147,7 +147,7 @@ mkdir boosapi && cd boosapi
cat > docker-compose.yml << 'EOF'
services:
boosapi:
image: 1467078763/metapi:latest
image: 1467078763/boosapi:latest
ports:
- "4000:4000"
volumes:
+2 -2
View File
@@ -1,6 +1,6 @@
apiVersion: v2
name: metapi
description: Minimal metapi chart for digest-aware k3s update-center setups
name: boosapi
description: Minimal boosapi chart for digest-aware k3s update-center setups
type: application
version: 0.1.0
appVersion: "1.3.0"
+10 -10
View File
@@ -4,9 +4,9 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "metapi.fullname" . }}
name: {{ include "boosapi.fullname" . }}
labels:
{{- include "metapi.labels" . | nindent 4 }}
{{- include "boosapi.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
revisionHistoryLimit: 2
@@ -17,25 +17,25 @@ spec:
maxUnavailable: {{ .Values.deployment.strategy.maxUnavailable }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "metapi.name" . }}
app.kubernetes.io/name: {{ include "boosapi.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "metapi.name" . }}
app.kubernetes.io/name: {{ include "boosapi.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
annotations:
metapi/image-tag: {{ .Values.image.tag | quote }}
metapi/image-digest: {{ .Values.image.digest | quote }}
boosapi/image-tag: {{ .Values.image.tag | quote }}
boosapi/image-digest: {{ .Values.image.digest | quote }}
checksum/env-secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum | quote }}
spec:
containers:
- name: metapi
- name: boosapi
image: "{{ .Values.image.repository }}{{ if .Values.image.digest }}@{{ .Values.image.digest }}{{ else }}:{{ .Values.image.tag }}{{ end }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
envFrom:
- secretRef:
name: {{ include "metapi.envSecretName" . }}
name: {{ include "boosapi.envSecretName" . }}
ports:
- name: http
containerPort: 4000
@@ -50,10 +50,10 @@ spec:
initialDelaySeconds: 30
periodSeconds: 20
volumeMounts:
- name: metapi-data
- name: boosapi-data
mountPath: /app/data
volumes:
- name: metapi-data
- name: boosapi-data
hostPath:
path: {{ .Values.persistence.hostPath }}
type: DirectoryOrCreate
+2 -2
View File
@@ -1,9 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ include "metapi.envSecretName" . }}
name: {{ include "boosapi.envSecretName" . }}
labels:
{{- include "metapi.labels" . | nindent 4 }}
{{- include "boosapi.labels" . | nindent 4 }}
type: Opaque
stringData:
AUTH_TOKEN: {{ required "env.authToken is required" .Values.env.authToken | quote }}
+3 -3
View File
@@ -1,13 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "metapi.fullname" . }}
name: {{ include "boosapi.fullname" . }}
labels:
{{- include "metapi.labels" . | nindent 4 }}
{{- include "boosapi.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
app.kubernetes.io/name: {{ include "metapi.name" . }}
app.kubernetes.io/name: {{ include "boosapi.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
ports:
- name: http
+2 -2
View File
@@ -1,7 +1,7 @@
replicaCount: 1
image:
repository: 1467078763/metapi
repository: 1467078763/boosapi
tag: latest
digest: ""
pullPolicy: Always
@@ -17,7 +17,7 @@ deployment:
maxUnavailable: 0
persistence:
hostPath: /opt/1panel/docker/compose/metapihub/data
hostPath: /opt/1panel/docker/compose/boosapihub/data
env:
authToken: ""
+16 -16
View File
@@ -1,17 +1,17 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: metapi-deploy-helper
name: boosapi-deploy-helper
namespace: ai
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: metapi-deploy-helper-admin
name: boosapi-deploy-helper-admin
namespace: ai
subjects:
- kind: ServiceAccount
name: metapi-deploy-helper
name: boosapi-deploy-helper
namespace: ai
roleRef:
apiGroup: rbac.authorization.k8s.io
@@ -21,7 +21,7 @@ roleRef:
apiVersion: v1
kind: Secret
metadata:
name: metapi-deploy-helper-auth
name: boosapi-deploy-helper-auth
namespace: ai
type: Opaque
stringData:
@@ -30,22 +30,22 @@ stringData:
apiVersion: apps/v1
kind: Deployment
metadata:
name: metapi-deploy-helper
name: boosapi-deploy-helper
namespace: ai
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: metapi-deploy-helper
app.kubernetes.io/name: boosapi-deploy-helper
template:
metadata:
labels:
app.kubernetes.io/name: metapi-deploy-helper
app.kubernetes.io/name: boosapi-deploy-helper
spec:
serviceAccountName: metapi-deploy-helper
serviceAccountName: boosapi-deploy-helper
containers:
- name: helper
image: 1467078763/metapi:latest
image: 1467078763/boosapi:latest
imagePullPolicy: Always
command: ["/bin/sh", "-lc"]
args:
@@ -85,7 +85,7 @@ spec:
- name: DEPLOY_HELPER_TOKEN
valueFrom:
secretKeyRef:
name: metapi-deploy-helper-auth
name: boosapi-deploy-helper-auth
key: DEPLOY_HELPER_TOKEN
readinessProbe:
httpGet:
@@ -100,23 +100,23 @@ spec:
initialDelaySeconds: 15
periodSeconds: 20
volumeMounts:
- name: metapi-chart
mountPath: /opt/metapi-k3s/chart
- name: boosapi-chart
mountPath: /opt/boosapi-k3s/chart
readOnly: true
volumes:
- name: metapi-chart
- name: boosapi-chart
hostPath:
path: /opt/metapi-k3s/chart
path: /opt/boosapi-k3s/chart
type: Directory
---
apiVersion: v1
kind: Service
metadata:
name: metapi-deploy-helper
name: boosapi-deploy-helper
namespace: ai
spec:
selector:
app.kubernetes.io/name: metapi-deploy-helper
app.kubernetes.io/name: boosapi-deploy-helper
ports:
- name: http
port: 9850
+12 -12
View File
@@ -1,4 +1,4 @@
FROM node:22-bookworm-slim AS metapi-builder
FROM node:22-bookworm-slim AS boosapi-builder
WORKDIR /app
RUN echo 'Acquire::http::Proxy "false";' > /etc/apt/apt.conf.d/99no-proxy && apt-get update && apt-get install -y --no-install-recommends python3 make g++ && rm -rf /var/lib/apt/lists/*
@@ -54,16 +54,16 @@ RUN git clone https://github.com/comfyanonymous/ComfyUI.git . \
&& rm -rf ~/.cache/pip
ENV PATH="/app/comfy/venv/bin:${PATH}"
# Copy metapi (built)
WORKDIR /app/metapi
COPY --from=metapi-builder /app/dist ./dist
COPY --from=metapi-builder /app/node_modules ./node_modules
COPY --from=metapi-builder /app/package.json ./
COPY --from=metapi-builder /app/drizzle ./drizzle
# Copy boosapi (built)
WORKDIR /app/boosapi
COPY --from=boosapi-builder /app/dist ./dist
COPY --from=boosapi-builder /app/node_modules ./node_modules
COPY --from=boosapi-builder /app/package.json ./
COPY --from=boosapi-builder /app/drizzle ./drizzle
RUN mkdir -p data
# Copy BoosAPI custom nodes for ComfyUI (call local BoosAPI API)
COPY --from=metapi-builder /app/boosapi_comfy_nodes.py /app/comfy/custom_nodes/boosapi_comfy_nodes.py
COPY --from=boosapi-builder /app/boosapi_comfy_nodes.py /app/comfy/custom_nodes/boosapi_comfy_nodes.py
# Supervisor config
RUN mkdir -p /var/log/supervisor
@@ -74,12 +74,12 @@ user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/tmp/supervisord.pid
[program:metapi]
[program:boosapi]
command=sh -c "node dist/server/db/migrate.js && node dist/server/index.js"
directory=/app/metapi
directory=/app/boosapi
autorestart=true
stdout_logfile=/var/log/supervisor/metapi.log
stderr_logfile=/var/log/supervisor/metapi.err
stdout_logfile=/var/log/supervisor/boosapi.log
stderr_logfile=/var/log/supervisor/boosapi.err
[program:comfyui]
command=python3 main.py --listen 0.0.0.0 --port 8188 --cpu
+1 -1
View File
@@ -2,7 +2,7 @@
# This file is automatically picked up by Docker Compose during local development.
# It overrides the image reference in docker-compose.yml with a local build.
services:
metapi:
boosapi:
image: ~
build:
context: ..
+2 -2
View File
@@ -1,6 +1,6 @@
services:
metapi:
image: 1467078763/metapi:latest
boosapi:
image: 1467078763/boosapi:latest
ports:
- "127.0.0.1:4000:4000"
volumes:
+2 -2
View File
@@ -72,7 +72,7 @@ export default withMermaid(
{ text: 'OAuth 管理', link: '/oauth' },
{ text: 'FAQ', link: '/faq' },
{ text: '文档维护', link: '/README' },
{ text: '项目主页', link: 'https://github.com/cita-777/metapi' },
{ text: '项目主页', link: 'https://github.com/cita-777/boosapi' },
],
sidebar: [
{
@@ -106,7 +106,7 @@ export default withMermaid(
},
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/cita-777/metapi' },
{ icon: 'github', link: 'https://github.com/cita-777/boosapi' },
],
outline: {
level: [2, 3],
+3 -3
View File
@@ -105,10 +105,10 @@ Metapi 暴露标准 OpenAI / Claude 兼容接口,下游客户端通常只需
```toml
model = "gpt-5"
model_provider = "metapi"
model_provider = "boosapi"
[model_providers.metapi]
name = "metapi"
[model_providers.boosapi]
name = "boosapi"
base_url = "https://your-domain.com/v1"
```
+2 -2
View File
@@ -161,7 +161,7 @@ Render 免费实例在 15 分钟无流量后会自动休眠。使用 UptimeRobot
### 标准步骤
```bash
mkdir metapi && cd metapi
mkdir boosapi && cd boosapi
# 创建 docker-compose.yml(参见快速上手)
# 设置环境变量
@@ -193,7 +193,7 @@ docker compose --env-file .env up -d
## Docker 命令部署
```bash
docker run -d --name metapi \
docker run -d --name boosapi \
-p 4000:4000 \
-e AUTH_TOKEN=your-admin-token \
-e PROXY_TOKEN=your-proxy-sk-token \
+3 -3
View File
@@ -26,7 +26,7 @@
### 1. 创建项目目录
```bash
mkdir metapi && cd metapi
mkdir boosapi && cd boosapi
```
### 2. 创建 `docker-compose.yml`
@@ -34,7 +34,7 @@ mkdir metapi && cd metapi
```yaml
services:
metapi:
image: 1467078763/metapi:latest
image: 1467078763/boosapi:latest
ports:
- "4000:4000"
volumes:
@@ -111,7 +111,7 @@ Linux 安装包选择建议:
```bash
git clone https://github.com/cita-777/metapi.git
cd metapi
cd boosapi
npm install
npm run db:migrate
npm run dev
+21 -21
View File
@@ -37,7 +37,7 @@ K3s 更新中心的日常入口位于:
| Deploy Helper URL | UI:设置 → 更新中心 | 例如集群内 Service 地址 |
| Namespace / Release Name / Chart Ref / Image Repository | UI:设置 → 更新中心 | 都是页面里直接填的部署配置 |
| GitHub Releases / Docker Hub / 默认部署来源 | UI:设置 → 更新中心 | 属于页面里的版本来源策略 |
| 主 Metapi 到 helper 的认证 token | 主 Metapi 环境变量 | `DEPLOY_HELPER_TOKEN` 或 `UPDATE_CENTER_HELPER_TOKEN` |
| 主 BoosAPI 到 helper 的认证 token | 主 BoosAPI 环境变量 | `DEPLOY_HELPER_TOKEN` 或 `UPDATE_CENTER_HELPER_TOKEN` |
| helper 自己监听在哪个地址和端口 | helper 环境变量 / manifest | `DEPLOY_HELPER_HOST` / `DEPLOY_HELPER_PORT` |
| helper 自己的 Bearer Token | helper 环境变量 / manifest | `DEPLOY_HELPER_TOKEN`,且必须与主服务一致 |
| chart 是否真的支持 digest 部署 | chart 文件本身 | 这不是 UI,也不是普通 env,要看 chart 模板 |
@@ -151,7 +151,7 @@ docker compose up -d
- `image.tag`
- `image.digest`
- 目标 Deployment 带有 `app.kubernetes.io/instance=<releaseName>` 标签
- 主 Metapi 服务可以访问:
- 主 BoosAPI 服务可以访问:
- GitHub API
- Docker Hub API
- Deploy Helper 的集群内地址
@@ -160,7 +160,7 @@ docker compose up -d
## helper 是什么
Deploy Helper 是一个跑在集群里的小服务。它不负责对外提供 Metapi 功能,只负责接受主 Metapi 发来的部署请求,然后在集群里执行:
Deploy Helper 是一个跑在集群里的小服务。它不负责对外提供 Metapi 功能,只负责接受主 BoosAPI 发来的部署请求,然后在集群里执行:
- `helm history`
- `helm get values`
@@ -202,7 +202,7 @@ Deploy Helper 是一个跑在集群里的小服务。它不负责对外提供 Me
仓库里带了一个最小示例清单:
- `deploy/k3s/metapi-deploy-helper.yaml`
- `deploy/k3s/boosapi-deploy-helper.yaml`
- `deploy/k3s/chart`
使用前至少要改这些值:
@@ -213,8 +213,8 @@ Deploy Helper 是一个跑在集群里的小服务。它不负责对外提供 Me
如果你准备直接按仓库示例接入,推荐把它们放到这两个路径:
- `/opt/metapi-k3s/metapi-deploy-helper.yaml`
- `/opt/metapi-k3s/chart`
- `/opt/boosapi-k3s/boosapi-deploy-helper.yaml`
- `/opt/boosapi-k3s/chart`
这里有一个很容易漏掉、但会直接决定更新中心是否真的可靠的约束:
@@ -223,16 +223,16 @@ Deploy Helper 是一个跑在集群里的小服务。它不负责对外提供 Me
这两个值必须指向同一份 chart。
如果你在设置页把 `Chart Ref` 填成 `/opt/metapi-k3s/chart`,但 helper Pod 里根本没有把那份 chart 挂进去,那么更新中心即使能看到版本,也无法稳定把 digest 部署到真正运行中的 Pod。
如果你在设置页把 `Chart Ref` 填成 `/opt/boosapi-k3s/chart`,但 helper Pod 里根本没有把那份 chart 挂进去,那么更新中心即使能看到版本,也无法稳定把 digest 部署到真正运行中的 Pod。
最小部署命令示例:
```bash
kubectl create namespace ai
mkdir -p /opt/metapi-k3s/chart
cp -R deploy/k3s/chart/. /opt/metapi-k3s/chart/
cp deploy/k3s/metapi-deploy-helper.yaml /opt/metapi-k3s/metapi-deploy-helper.yaml
kubectl apply -f /opt/metapi-k3s/metapi-deploy-helper.yaml
mkdir -p /opt/boosapi-k3s/chart
cp -R deploy/k3s/chart/. /opt/boosapi-k3s/chart/
cp deploy/k3s/boosapi-deploy-helper.yaml /opt/boosapi-k3s/boosapi-deploy-helper.yaml
kubectl apply -f /opt/boosapi-k3s/boosapi-deploy-helper.yaml
```
### 1.1 首次接入前一定要做的自检
@@ -255,8 +255,8 @@ kubectl apply -f /opt/metapi-k3s/metapi-deploy-helper.yaml
你可以在接入前先跑一次自检:
```bash
helm template metapi /opt/metapi-k3s/chart \
--set image.repository=1467078763/metapi \
helm template boosapi /opt/boosapi-k3s/chart \
--set image.repository=1467078763/boosapi \
--set image.tag=latest \
--set-string image.digest=sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
| grep -n 'image:'
@@ -264,17 +264,17 @@ helm template metapi /opt/metapi-k3s/chart \
你期望看到的是:
- `image: "1467078763/metapi@sha256:..."`
- `image: "1467078763/boosapi@sha256:..."`
如果输出仍然是:
- `image: "1467078763/metapi:latest"`
- `image: "1467078763/boosapi:latest"`
那说明这份 chart 还是 tag 语义,先不要继续配置更新中心。
### 2. 让主 Metapi 和 helper 用同一个 token
### 2. 让主 BoosAPI 和 helper 用同一个 token
主 Metapi 端支持这两个环境变量,设置一个即可:
主 BoosAPI 端支持这两个环境变量,设置一个即可:
- `DEPLOY_HELPER_TOKEN`
- `UPDATE_CENTER_HELPER_TOKEN`
@@ -295,11 +295,11 @@ helper 端使用:
| 字段 | 怎么理解 | 典型示例 |
|------|--------|----------|
| `Deploy Helper URL` | 主 Metapi 访问 helper 的地址 | `http://metapi-deploy-helper.ai.svc.cluster.local:9850` |
| `Deploy Helper URL` | 主 BoosAPI 访问 helper 的地址 | `http://boosapi-deploy-helper.ai.svc.cluster.local:9850` |
| `Namespace` | 目标 release 所在命名空间 | `ai` |
| `Release Name` | Helm release 名 | `metapi` |
| `Chart Ref` | helper Pod 能访问到的 chart 引用 | `/opt/metapi-k3s/chart` |
| `Image Repository` | 升级时写入 chart 的镜像仓库 | `1467078763/metapi` |
| `Chart Ref` | helper Pod 能访问到的 chart 引用 | `/opt/boosapi-k3s/chart` |
| `Image Repository` | 升级时写入 chart 的镜像仓库 | `1467078763/boosapi` |
| `默认部署来源` | 默认从 GitHub 还是 Docker Hub 取版本 | `GitHub Releases` |
另外还有 3 个开关:
@@ -395,7 +395,7 @@ About 页里的“更新提醒”更像一个轻量入口:
如果你是第一次接入,最稳妥的方式就是直接从仓库自带的:
- `deploy/k3s/chart`
- `deploy/k3s/metapi-deploy-helper.yaml`
- `deploy/k3s/boosapi-deploy-helper.yaml`
开始,不要自己先抄一份简化版再改。
+2 -2
View File
@@ -1,4 +1,4 @@
appId: me.cita777.metapi.desktop
appId: me.cita777.boosapi.desktop
productName: Metapi
artifactName: ${name}-${version}-${os}-${arch}.${ext}
directories:
@@ -31,7 +31,7 @@ linux:
publish:
provider: github
owner: cita-777
repo: metapi
repo: boosapi
releaseType: release
publishAutoUpdate: true
nsis:
+2 -2
View File
@@ -1,11 +1,11 @@
{
"name": "metapi",
"name": "boosapi",
"version": "1.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "metapi",
"name": "boosapi",
"version": "1.3.0",
"license": "MIT",
"dependencies": {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "metapi",
"name": "boosapi",
"version": "1.3.0",
"description": "Meta-layer management and unified proxy for AI API aggregation platforms",
"main": "dist/desktop/main.js",
+10 -12
View File
@@ -17,25 +17,23 @@
| 后端通知 | `notifyService.ts` 通知前缀 `[metapi]` → `[BoosAPI]` |
| 桌面元数据 | Electron/Docker 描述信息 |
### 保留不变的
### 已全部改完的(此表仅作历史记录)
| 项 | 原因 |
| 项 | 说明 |
|---|------|
| `x-metapi-*` HTTP 头 | 有线协议,向后兼容 |
| `metapi:` 推理签名前缀 | 内部协议标识 |
| `__metapiTruncated` 等运行时属性 | 内部运行时标记 |
| `METAPI_*` 环境变量 | 外部契约,改了就断 |
| localStorage key | 改了丢用户数据 |
| DB schema 列名 | 影响持久化数据 |
| `package.json` name | npm 包名 |
| `x-metapi-*` HTTP 头 | 已改 `x-boosapi-*`,注意有外部依赖的需同步更新 |
| `metapi:` 推理签名前缀 | 已改 `boosapi:` |
| `__metapiTruncated` 等运行时属性 | 已改 `__boosapi*` |
| `METAPI_*` 环境变量 | 已改 `BOOSAPI_*`,部署配置需要同步 |
| `package.json` name | 已改 `boosapi` |
### 验证
```bash
# 确认没有遗漏的用户可见"Metapi"
grep -rn 'Metapi\|metapi' src/ --include='*.ts' --include='*.tsx' --include='*.html' \
# 确认没有遗漏的 metapi
grep -rn 'mM]etapi' src/ --include='*.ts' --include='*.tsx' --include='*.html' \
| grep -v '.test.' | grep -v node_modules | grep -iv 'boosapi'
# 剩余应只有 x-metapi、metapi:、__metapi 等内部标识
# 应无输出
```
---
+2 -2
View File
@@ -1,8 +1,8 @@
services:
- type: web
name: metapi
name: boosapi
runtime: docker
repo: https://github.com/cita-777/metapi
repo: https://github.com/cita-777/boosapi
dockerfilePath: ./docker/Dockerfile
dockerContext: .
plan: free
+1 -1
View File
@@ -37,7 +37,7 @@ async function ensureBetterSqliteCompatible() {
}
const rebuild = buildBetterSqliteRebuildCommand();
console.log('[metapi] Detected better-sqlite3 ABI mismatch. Rebuilding for the current Node.js runtime...');
console.log('[boosapi] Detected better-sqlite3 ABI mismatch. Rebuilding for the current Node.js runtime...');
await run(rebuild.command, rebuild.args);
try {
+3 -3
View File
@@ -3,10 +3,10 @@ import { readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const REPO = 'cita-777/metapi';
const REPO = 'cita-777/boosapi';
const README_FILES = ['README.md', 'README_EN.md'] as const;
const START_MARKER = '<!-- metapi-contributors:start -->';
const END_MARKER = '<!-- metapi-contributors:end -->';
const START_MARKER = '<!-- boosapi-contributors:start -->';
const END_MARKER = '<!-- boosapi-contributors:end -->';
const PER_LINE = 10;
const EXCLUDED_LOGINS = new Set(['dependabot[bot]']);
+2 -2
View File
@@ -61,13 +61,13 @@ function getWindowIconPath() {
}
function resolveFrontendUrl() {
const devUrl = (process.env.METAPI_DESKTOP_DEV_SERVER_URL || '').trim();
const devUrl = (process.env.BOOSAPI_DESKTOP_DEV_SERVER_URL || '').trim();
if (devUrl) return devUrl;
return serverUrl;
}
function resolveExternalServerUrl() {
return (process.env.METAPI_DESKTOP_EXTERNAL_SERVER_URL || '').trim();
return (process.env.BOOSAPI_DESKTOP_EXTERNAL_SERVER_URL || '').trim();
}
function showMainWindow() {
+3 -3
View File
@@ -39,8 +39,8 @@ export function buildDesktopServerEnv(input: DesktopServerEnvInput): NodeJS.Proc
HOST: host,
PORT: String(input.port),
DATA_DIR: input.userDataDir,
METAPI_DESKTOP: '1',
METAPI_LOG_DIR: input.logsDir,
BOOSAPI_DESKTOP: '1',
BOOSAPI_LOG_DIR: input.logsDir,
};
}
@@ -53,7 +53,7 @@ export function createDesktopHealthUrl(port: number): string {
}
export function resolveDesktopServerPort(env?: NodeJS.ProcessEnv): number {
const forcedPort = Number.parseInt(env?.METAPI_DESKTOP_SERVER_PORT || '', 10);
const forcedPort = Number.parseInt(env?.BOOSAPI_DESKTOP_SERVER_PORT || '', 10);
if (Number.isFinite(forcedPort) && forcedPort > 0) return forcedPort;
return DEFAULT_DESKTOP_SERVER_PORT;
}
+2 -2
View File
@@ -6,8 +6,8 @@ import { tokenRouter } from '../services/tokenRouter.js';
type SelectedChannel = Awaited<ReturnType<typeof tokenRouter.selectChannel>>;
export const TESTER_FORCED_CHANNEL_HEADER = 'x-metapi-tester-forced-channel-id';
export const TESTER_REQUEST_HEADER = 'x-metapi-tester-request';
export const TESTER_FORCED_CHANNEL_HEADER = 'x-boosapi-tester-forced-channel-id';
export const TESTER_REQUEST_HEADER = 'x-boosapi-tester-request';
function headerValueEquals(
headers: Record<string, unknown> | undefined,
@@ -54,7 +54,7 @@ function normalizeLowerCaseHeaderMap(
}
export function uuidFromSeed(seed: string): string {
const derived = pbkdf2Sync(seed, 'metapi-runtime-header-seed', 10_000, 16, 'sha256');
const derived = pbkdf2Sync(seed, 'boosapi-runtime-header-seed', 10_000, 16, 'sha256');
const bytes = new Uint8Array(derived);
bytes[6] = (bytes[6]! & 0x0f) | 0x50;
bytes[8] = (bytes[8]! & 0x3f) | 0x80;
@@ -159,7 +159,7 @@ export function buildCodexRuntimeHeaders(input: {
getInputHeader(input.baseHeaders, 'session_id')
|| getInputHeader(input.baseHeaders, 'session-id')
|| explicitSessionId
|| (continuityKey ? uuidFromSeed(`metapi:codex:${continuityKey}`) : null)
|| (continuityKey ? uuidFromSeed(`boosapi:codex:${continuityKey}`) : null)
|| randomUUID()
);
const conversationId = (
@@ -124,7 +124,7 @@ function getCodexSessionHeaderValue(headers: Record<string, string>): string {
}
function isResponsesWebsocketTransportRequest(headers: Record<string, unknown>): boolean {
return Object.entries(headers)
.some(([rawKey, rawValue]) => rawKey.trim().toLowerCase() === 'x-metapi-responses-websocket-transport'
.some(([rawKey, rawValue]) => rawKey.trim().toLowerCase() === 'x-boosapi-responses-websocket-transport'
&& String(rawValue).trim() === '1');
}
+4 -4
View File
@@ -1,7 +1,7 @@
import { FastifyInstance } from 'fastify';
import { fetch } from 'undici';
const METAPI_BASE = `http://127.0.0.1:${process.env.PORT || 3000}`;
const BOOSAPI_BASE = `http://127.0.0.1:${process.env.PORT || 3000}`;
interface AgentRequest {
script: string;
@@ -72,7 +72,7 @@ const SCENE_PROMPT_GEN = `根据场景描述生成图像生成提示词,用于
只返回 JSON。`;
async function callLLM(prompt: string, system: string): Promise<string> {
const resp = await fetch(`${METAPI_BASE}/v1/chat/completions`, {
const resp = await fetch(`${BOOSAPI_BASE}/v1/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -92,7 +92,7 @@ async function callLLM(prompt: string, system: string): Promise<string> {
}
async function callImageGen(prompt: string): Promise<string> {
const resp = await fetch(`${METAPI_BASE}/v1/images/generations`, {
const resp = await fetch(`${BOOSAPI_BASE}/v1/images/generations`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -110,7 +110,7 @@ async function callImageGen(prompt: string): Promise<string> {
}
async function callTTS(text: string, voice = 'alloy'): Promise<Buffer | null> {
const resp = await fetch(`${METAPI_BASE}/v1/audio/speech`, {
const resp = await fetch(`${BOOSAPI_BASE}/v1/audio/speech`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
+3 -3
View File
@@ -1,7 +1,7 @@
import type { FastifyInstance, FastifyRequest } from 'fastify';
type MultipartAwareFastify = FastifyInstance & {
__metapiMultipartParserRegistered?: boolean;
__boosapiMultipartParserRegistered?: boolean;
};
function getContentType(request: FastifyRequest): string {
@@ -12,13 +12,13 @@ function getContentType(request: FastifyRequest): string {
export function ensureMultipartBufferParser(app: FastifyInstance): void {
const target = app as MultipartAwareFastify;
if (target.__metapiMultipartParserRegistered) return;
if (target.__boosapiMultipartParserRegistered) return;
app.addContentTypeParser(/^multipart\/form-data(?:;.*)?$/i, { parseAs: 'buffer' }, (_request, body, done) => {
done(null, body);
});
target.__metapiMultipartParserRegistered = true;
target.__boosapiMultipartParserRegistered = true;
}
export function isMultipartRequest(request: FastifyRequest): boolean {
@@ -22,8 +22,8 @@ import { applyOpenAiServiceTierPolicy } from '../../proxy-core/serviceTierPolicy
const installedApps = new WeakSet<FastifyInstance>();
const WS_TURN_STATE_HEADER = 'x-codex-turn-state';
const RESPONSES_WEBSOCKET_MODE_HEADER = 'x-metapi-responses-websocket-mode';
const RESPONSES_WEBSOCKET_TRANSPORT_HEADER = 'x-metapi-responses-websocket-transport';
const RESPONSES_WEBSOCKET_MODE_HEADER = 'x-boosapi-responses-websocket-mode';
const RESPONSES_WEBSOCKET_TRANSPORT_HEADER = 'x-boosapi-responses-websocket-transport';
const codexWebsocketRuntime = createCodexWebsocketRuntime();
type SelectedChannel = NonNullable<Awaited<ReturnType<typeof tokenRouter.selectChannel>>>;
+2 -2
View File
@@ -27,7 +27,7 @@ let lastPruneAtMs = 0;
const PRUNE_INTERVAL_MS = 5 * 60 * 1000;
type TruncatedDebugPreview = {
__metapiTruncated: true;
__boosapiTruncated: true;
preview: string;
originalBytes: number;
storedBytes: number;
@@ -36,7 +36,7 @@ type TruncatedDebugPreview = {
function buildTruncatedDebugPreview(text: string, maxBytes: number, originalBytes: number): string {
const truncated = Buffer.from(text, 'utf8').subarray(0, Math.max(0, maxBytes)).toString('utf8');
const payload: TruncatedDebugPreview = {
__metapiTruncated: true,
__boosapiTruncated: true,
preview: truncated,
originalBytes,
storedBytes: maxBytes,
+1 -1
View File
@@ -4,7 +4,7 @@ import { db, schema } from '../db/index.js';
import type { ProxyResourceOwner } from '../middleware/auth.js';
import { formatUtcSqlDateTime } from './localTimeService.js';
export const LOCAL_PROXY_FILE_ID_PREFIX = 'file-metapi-';
export const LOCAL_PROXY_FILE_ID_PREFIX = 'file-boosapi-';
export type ProxyFileRecord = {
publicId: string;
@@ -85,19 +85,19 @@ const GENERIC_PASSTHROUGH_ALLOWED_HEADERS = new Set([
'x-codex-turn-metadata',
'x-codex-turn-state',
]);
const METAPI_INTERNAL_HEADER_BLOCKLIST = new Set([
'x-metapi-tester-request',
'x-metapi-tester-forced-channel-id',
'x-metapi-responses-websocket-mode',
'x-metapi-responses-websocket-transport',
const BOOSAPI_INTERNAL_HEADER_BLOCKLIST = new Set([
'x-boosapi-tester-request',
'x-boosapi-tester-forced-channel-id',
'x-boosapi-responses-websocket-mode',
'x-boosapi-responses-websocket-transport',
]);
const ANTIGRAVITY_RUNTIME_USER_AGENT = 'antigravity/1.19.6 darwin/arm64';
function shouldSkipPassthroughHeader(key: string): boolean {
if (HOP_BY_HOP_HEADERS.has(key) || BLOCKED_PASSTHROUGH_HEADERS.has(key)) return true;
if (METAPI_INTERNAL_HEADER_BLOCKLIST.has(key)) return true;
if (key.startsWith('x-metapi-')) return true;
if (BOOSAPI_INTERNAL_HEADER_BLOCKLIST.has(key)) return true;
if (key.startsWith('x-boosapi-')) return true;
if (!GENERIC_PASSTHROUGH_ALLOWED_HEADERS.has(key)) return true;
return false;
}
@@ -645,9 +645,9 @@ export function buildUpstreamEndpointRequest(input: {
if (input.endpoint === 'responses') {
const responsesWebsocketTransport = getInputHeader(
input.downstreamHeaders,
'x-metapi-responses-websocket-transport',
'x-boosapi-responses-websocket-transport',
) === '1';
const websocketMode = Object.entries(input.downstreamHeaders || {}).find(([rawKey]) => rawKey.trim().toLowerCase() === 'x-metapi-responses-websocket-mode');
const websocketMode = Object.entries(input.downstreamHeaders || {}).find(([rawKey]) => rawKey.trim().toLowerCase() === 'x-boosapi-responses-websocket-mode');
const preserveWebsocketIncrementalMode = asTrimmedString(websocketMode?.[1]).toLowerCase() === 'incremental';
const responsesHeaders = input.downstreamFormat === 'responses'
? extractResponsesPassthroughHeaders(input.downstreamHeaders)
@@ -350,7 +350,7 @@ function resolveAnthropicThinkingSignature(item: Record<string, unknown>): strin
if (decodedTaggedSignature !== null) {
return decodedTaggedSignature;
}
if (item.reasoning_signature !== undefined || rawSignature.startsWith('metapi:')) {
if (item.reasoning_signature !== undefined || rawSignature.startsWith('boosapi:')) {
return null;
}
return rawSignature;
@@ -51,7 +51,7 @@ function cleanAnthropicReasoningSignature(value: unknown): string | null {
if (!raw) return null;
const decoded = decodeAnthropicReasoningSignature(raw);
if (decoded) return decoded;
if (raw.startsWith('metapi:')) return null;
if (raw.startsWith('boosapi:')) return null;
return raw;
}
@@ -78,7 +78,7 @@ function cleanAnthropicReasoningSignature(value: unknown): string | null {
if (!raw) return null;
const decoded = decodeAnthropicReasoningSignature(raw);
if (decoded) return decoded;
if (raw.startsWith('metapi:')) return null;
if (raw.startsWith('boosapi:')) return null;
return raw;
}
@@ -1,6 +1,6 @@
import type { CanonicalContinuation } from './types.js';
export const OPENAI_CONTINUATION_TURN_STATE_METADATA_KEY = 'metapi_turn_state';
export const OPENAI_CONTINUATION_TURN_STATE_METADATA_KEY = 'boosapi_turn_state';
function asTrimmedString(value: unknown): string {
return typeof value === 'string' ? value.trim() : '';
@@ -19,10 +19,10 @@ function cloneJsonValue<T>(value: T): T {
}
const RESPONSES_MCP_COMPAT_MARKER = 'responses_mcp_item';
const RESPONSES_MCP_COMPAT_PREFIX = 'metapi_mcp_item__';
const RESPONSES_MCP_COMPAT_PREFIX = 'boosapi_mcp_item__';
type ResponsesMcpCompatEnvelope = {
metapi_compat: typeof RESPONSES_MCP_COMPAT_MARKER;
boosapi_compat: typeof RESPONSES_MCP_COMPAT_MARKER;
itemType: string;
item: Record<string, unknown>;
};
@@ -38,7 +38,7 @@ function createResponsesMcpCompatEnvelope(
if (!itemType.startsWith('mcp_')) return null;
return {
metapi_compat: RESPONSES_MCP_COMPAT_MARKER,
boosapi_compat: RESPONSES_MCP_COMPAT_MARKER,
itemType,
item: cloneJsonValue(item),
};
@@ -81,14 +81,14 @@ function parseCompatEnvelope(rawArguments: unknown): ResponsesMcpCompatEnvelope
try {
const parsed = JSON.parse(trimmed) as unknown;
if (!isRecord(parsed)) return null;
if (asTrimmedString(parsed.metapi_compat) !== RESPONSES_MCP_COMPAT_MARKER) return null;
if (asTrimmedString(parsed.boosapi_compat) !== RESPONSES_MCP_COMPAT_MARKER) return null;
const itemType = asTrimmedString(parsed.itemType).toLowerCase();
if (!itemType.startsWith('mcp_')) return null;
if (!isRecord(parsed.item)) return null;
return {
metapi_compat: RESPONSES_MCP_COMPAT_MARKER,
boosapi_compat: RESPONSES_MCP_COMPAT_MARKER,
itemType,
item: cloneJsonValue(parsed.item),
};
@@ -361,7 +361,7 @@ export function buildNormalizedFinalToOpenAiResponsesPayload(input: {
? normalized.reasoningSignature.trim()
: '';
const encryptedReasoning = decodeOpenAiEncryptedReasoning(rawReasoningSignature)
?? (rawReasoningSignature && !rawReasoningSignature.startsWith('metapi:') ? rawReasoningSignature : null);
?? (rawReasoningSignature && !rawReasoningSignature.startsWith('boosapi:') ? rawReasoningSignature : null);
const annotations = extractAnnotationsFromUpstream(upstreamPayload);
const output: Array<Record<string, unknown>> = syntheticOutput.map((item) => cloneJson(item));
@@ -2251,7 +2251,7 @@ export function serializeFinalResponse(
const rawReasoningSignature = typeof normalized.reasoningSignature === 'string'
? normalized.reasoningSignature.trim()
: '';
const taggedReasoningSignature = rawReasoningSignature.startsWith('metapi:');
const taggedReasoningSignature = rawReasoningSignature.startsWith('boosapi:');
const claudeReasoningSignature = decodeAnthropicReasoningSignature(rawReasoningSignature)
?? (rawReasoningSignature && !taggedReasoningSignature ? rawReasoningSignature : null);
@@ -1,4 +1,4 @@
const PROVIDER_PREFIX = 'metapi';
const PROVIDER_PREFIX = 'boosapi';
export const ANTHROPIC_REASONING_SIGNATURE_PREFIX = `${PROVIDER_PREFIX}:anthropic-signature:`;
export const GEMINI_THOUGHT_SIGNATURE_PREFIX = `${PROVIDER_PREFIX}:gemini-thought-signature:`;
+1 -1
View File
@@ -259,7 +259,7 @@ export const zhToEnSupplemental: Record<string, string> = {
'拉取分组失败': 'Failed to pull group',
'拉取分组失败,已回退 default': 'Failed to pull the group and has fallen back to default',
'冷却中': 'Cooling down',
'例如 BoosAPI': 'For example metapi',
'例如 BoosAPI': 'For example BoosAPI',
'例如: admin@example.com': 'For example: admin@example.com',
'例如: smtp.qq.com': 'For example: smtp.qq.com',
'例如: target@example.com': 'For example: target@example.com',
+5 -5
View File
@@ -4,8 +4,8 @@ metadata:
name: Metapi
spec:
description: Meta-layer management and unified proxy for AI API aggregation platforms.
icon: https://raw.githubusercontent.com/cita-777/metapi/main/docs/logos/logo-icon-512.png
coverImage: https://raw.githubusercontent.com/cita-777/metapi/main/docs/logos/logo-banner.png
icon: https://raw.githubusercontent.com/cita-777/boosapi/main/docs/logos/logo-icon-512.png
coverImage: https://raw.githubusercontent.com/cita-777/boosapi/main/docs/logos/logo-banner.png
tags:
- AI
- Tool
@@ -41,12 +41,12 @@ spec:
name: Service Port
description: Internal HTTP port (default 4000).
services:
- name: metapi
icon: https://raw.githubusercontent.com/cita-777/metapi/main/docs/logos/logo-icon-512.png
- name: boosapi
icon: https://raw.githubusercontent.com/cita-777/boosapi/main/docs/logos/logo-icon-512.png
template: PREBUILT
spec:
source:
image: 1467078763/metapi:latest
image: 1467078763/boosapi:latest
ports:
- id: web
port: 4000