feat: rebrand Metapi to BoosAPI, add ComfyUI agent and user management

- Rename project from Metapi to BoosAPI across all UI and server strings
- Add ComfyUI conversational agent page (/comfyui-agent)
- Add user management system (register, login, API keys, admin)
- Update Dockerfile and database schema
- Add ComfyUI workflow nodes support
- Update shared contracts and platform configurations

Signed-off-by: Boos4721 <boos4721@icloud.com>
This commit is contained in:
2026-05-15 20:20:58 +08:00
parent cdb12a9819
commit 9cfe8427b5
91 changed files with 13595 additions and 1358 deletions
+41
View File
@@ -3,6 +3,7 @@ import { FastifyRequest, FastifyReply } from 'fastify';
import { config } from '../config.js';
import { authorizeDownstreamToken, consumeManagedKeyRequest } from '../services/downstreamApiKeyService.js';
import { EMPTY_DOWNSTREAM_ROUTING_POLICY, type DownstreamRoutingPolicy } from '../services/downstreamPolicyTypes.js';
import { verifyJwt, type JwtPayload } from '../services/userService.js';
export interface ProxyAuthContext {
token: string;
@@ -17,7 +18,14 @@ export interface ProxyResourceOwner {
ownerId: string;
}
export interface UserAuthContext {
userId: number;
email: string;
role: 'admin' | 'user';
}
const proxyAuthContextByRequest = new WeakMap<FastifyRequest, ProxyAuthContext>();
const userAuthContextByRequest = new WeakMap<FastifyRequest, UserAuthContext>();
type ParsedAllowlistEntry =
| { kind: 'exact'; normalizedIp: string }
@@ -190,3 +198,36 @@ export function getProxyResourceOwner(request: FastifyRequest): ProxyResourceOwn
ownerId: 'global',
};
}
export async function userAuthMiddleware(request: FastifyRequest, reply: FastifyReply) {
const auth = request.headers.authorization;
if (!auth || !auth.startsWith('Bearer ')) {
reply.code(401).send({ error: 'Missing or invalid Authorization header' });
return;
}
const token = auth.slice('Bearer '.length).trim();
const payload = verifyJwt(token);
if (!payload) {
reply.code(401).send({ error: 'Invalid or expired token' });
return;
}
userAuthContextByRequest.set(request, {
userId: payload.userId,
email: payload.email,
role: payload.role,
});
}
export function getUserAuthContext(request: FastifyRequest): UserAuthContext | null {
return userAuthContextByRequest.get(request) || null;
}
export async function requireAdmin(request: FastifyRequest, reply: FastifyReply) {
const user = getUserAuthContext(request);
if (!user || user.role !== 'admin') {
reply.code(403).send({ error: 'Admin access required' });
return;
}
}