@sleep2agi/commhub-server 0.5.0-preview.21 → 0.5.0-preview.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/commhub-server",
3
- "version": "0.5.0-preview.21",
3
+ "version": "0.5.0-preview.22",
4
4
  "description": "CommHub MCP Server — AI Agent communication hub with SSE push, MCP protocol, and REST API",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/auth.ts CHANGED
@@ -139,6 +139,17 @@ export function listTokens(userId: string) {
139
139
  ).all(userId);
140
140
  }
141
141
 
142
+ export function deleteNetwork(userId: string, networkId: string): { ok: boolean; error?: string } {
143
+ const net = db.query<any, [string]>("SELECT * FROM networks WHERE network_id = ?1").get(networkId);
144
+ if (!net) return { ok: false, error: "network not found" };
145
+ if (net.owner_id !== userId) return { ok: false, error: "not your network" };
146
+ // Check if any sessions/tasks still reference this network
147
+ const sessions = db.query<{ cnt: number }, [string]>("SELECT COUNT(*) as cnt FROM sessions WHERE network_id = ?1").get(networkId);
148
+ if (sessions && sessions.cnt > 0) return { ok: false, error: `network has ${sessions.cnt} active session(s) — stop them first` };
149
+ db.run("DELETE FROM networks WHERE network_id = ?1 AND owner_id = ?2", [networkId, userId]);
150
+ return { ok: true };
151
+ }
152
+
142
153
  export function createToken(userId: string, name: string, networkId?: string): { ok: boolean; token?: string; token_id?: string; error?: string } {
143
154
  const token = generateToken();
144
155
  const tokenId = generateId("tok");
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ import { z } from "zod/v4";
4
4
  import { registerTools } from "./tools.js";
5
5
  import { db, logTaskEvent, logAudit } from "./db.js";
6
6
  import { createSSEStream, pushEvent, pushBroadcast, getSSEStats } from "./push.js";
7
- import { register, login, resolveToken, getUserNetworks, createNetwork, changePassword, listTokens, createToken, revokeToken, type AuthUser } from "./auth.js";
7
+ import { register, login, resolveToken, getUserNetworks, createNetwork, deleteNetwork, changePassword, listTokens, createToken, revokeToken, type AuthUser } from "./auth.js";
8
8
 
9
9
  const PORT = Number(process.env.PORT) || 9200;
10
10
  const AUTH_TOKEN = process.env.COMMHUB_AUTH_TOKEN;
@@ -400,6 +400,16 @@ Bun.serve({
400
400
  }));
401
401
  }
402
402
 
403
+ if (netDetailMatch && req.method === "DELETE") {
404
+ const token = req.headers.get("Authorization")?.replace("Bearer ", "") || url.searchParams.get("token");
405
+ if (!token) return withCors(req, Response.json({ ok: false, error: "auth required" }, { status: 401 }));
406
+ const resolved = resolveToken(token);
407
+ if (!resolved) return withCors(req, Response.json({ ok: false, error: "invalid token" }, { status: 401 }));
408
+ const result = deleteNetwork(resolved.user.user_id, netDetailMatch[1]);
409
+ if (result.ok) logAudit(resolved.user.user_id, resolved.user.username, "network_deleted", "network", netDetailMatch[1]);
410
+ return withCors(req, Response.json(result, { status: result.ok ? 200 : 400 }));
411
+ }
412
+
403
413
  // ── REST: health (public, no auth) ──
404
414
  if (url.pathname === "/health") {
405
415
  const count = db.query<{ cnt: number }, []>("SELECT COUNT(*) as cnt FROM sessions").get();