MCPcopy Create free account
hub / github.com/MemTensor/MemOS / handle

Method handle

packages/memos-core/src/hub/server.ts:273–1075  ·  view source on GitHub ↗
(req: http.IncomingMessage, res: http.ServerResponse)

Source from the content-addressed store, hash-verified

271 }
272
273 private async handle(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
274 const url = new URL(req.url || "/", `http://127.0.0.1:${this.port}`);
275 const routePath = url.pathname;
276
277 if (req.method === "GET" && routePath === "/api/v1/hub/info") {
278 return this.json(res, 200, {
279 teamName: this.teamName,
280 version: "0.0.0",
281 apiVersion: "v1",
282 hubInstanceId: this.hubInstanceId,
283 });
284 }
285
286 if (req.method === "POST" && routePath === "/api/v1/hub/join") {
287 const body = await this.readJson(req);
288 if (!body || body.teamToken !== this.teamToken) {
289 return this.json(res, 403, { error: "invalid_team_token" });
290 }
291 const username = String(body.username || `user-${randomUUID().slice(0, 8)}`);
292 const joinIp = (typeof body.clientIp === "string" && body.clientIp)
293 || (req.headers["x-client-ip"] as string)?.trim()
294 || (req.headers["x-forwarded-for"] as string)?.split(",")[0]?.trim()
295 || req.socket.remoteAddress || "";
296 const identityKey = typeof body.identityKey === "string" ? body.identityKey.trim() : "";
297 const dryRun = body.dryRun === true;
298
299 const identityMatch = identityKey
300 ? this.userManager.findByIdentityKey(identityKey)
301 : null;
302
303 if (identityMatch) {
304 if (!dryRun) {
305 try { this.opts.store.updateHubUserActivity(identityMatch.id, joinIp); } catch { /* best-effort */ }
306 }
307
308 if (identityMatch.status === "active") {
309 if (dryRun) return this.json(res, 200, { status: "active", dryRun: true });
310 const token = issueUserToken(
311 { userId: identityMatch.id, username: identityMatch.username, role: identityMatch.role, status: "active" },
312 this.authSecret,
313 );
314 this.userManager.approveUser(identityMatch.id, token);
315 return this.json(res, 200, { status: "active", userId: identityMatch.id, userToken: token, identityKey: identityMatch.identityKey || identityKey });
316 }
317 if (identityMatch.status === "pending") {
318 if (dryRun) return this.json(res, 200, { status: "pending", dryRun: true });
319 this.notifyAdmins("user_join_request", "user", identityMatch.username, "", { dedup: true });
320 return this.json(res, 200, { status: "pending", userId: identityMatch.id, identityKey: identityMatch.identityKey || identityKey });
321 }
322 if (identityMatch.status === "rejected") {
323 if (dryRun) return this.json(res, 200, { status: "rejected", dryRun: true });
324 if (body.reapply === true) {
325 this.userManager.resetToPending(identityMatch.id);
326 this.notifyAdmins("user_join_request", "user", identityMatch.username, "");
327 this.opts.log.info(`Hub: rejected user "${identityMatch.username}" (${identityMatch.id}) re-applied, reset to pending`);
328 return this.json(res, 200, { status: "pending", userId: identityMatch.id, identityKey: identityMatch.identityKey || identityKey });
329 }
330 return this.json(res, 200, { status: "rejected", userId: identityMatch.id });

Callers 1

startMethod · 0.95

Calls 15

jsonMethod · 0.95
readJsonMethod · 0.95
notifyAdminsMethod · 0.95
authenticateMethod · 0.95
checkRateLimitMethod · 0.95
saveAuthStateMethod · 0.95
embedChunksAsyncMethod · 0.95
embedMemoryAsyncMethod · 0.95
embedSkillAsyncMethod · 0.95
issueUserTokenFunction · 0.90
filterMethod · 0.80
mapMethod · 0.80

Tested by

no test coverage detected