@sleep2agi/commhub-server 0.5.0-preview.21 → 0.5.0-preview.23
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 +1 -1
- package/src/auth.ts +21 -0
- package/src/index.ts +29 -1
package/package.json
CHANGED
package/src/auth.ts
CHANGED
|
@@ -139,6 +139,27 @@ export function listTokens(userId: string) {
|
|
|
139
139
|
).all(userId);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
export function renameNetwork(userId: string, networkId: string, newName: 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
|
+
const dup = db.query<any, [string, string]>("SELECT network_id FROM networks WHERE owner_id = ?1 AND network_name = ?2").get(userId, newName);
|
|
147
|
+
if (dup) return { ok: false, error: "name already taken" };
|
|
148
|
+
db.run("UPDATE networks SET network_name = ?1, updated_at = datetime('now') WHERE network_id = ?2", [newName, networkId]);
|
|
149
|
+
return { ok: true };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function deleteNetwork(userId: string, networkId: string): { ok: boolean; error?: string } {
|
|
153
|
+
const net = db.query<any, [string]>("SELECT * FROM networks WHERE network_id = ?1").get(networkId);
|
|
154
|
+
if (!net) return { ok: false, error: "network not found" };
|
|
155
|
+
if (net.owner_id !== userId) return { ok: false, error: "not your network" };
|
|
156
|
+
// Check if any sessions/tasks still reference this network
|
|
157
|
+
const sessions = db.query<{ cnt: number }, [string]>("SELECT COUNT(*) as cnt FROM sessions WHERE network_id = ?1").get(networkId);
|
|
158
|
+
if (sessions && sessions.cnt > 0) return { ok: false, error: `network has ${sessions.cnt} active session(s) — stop them first` };
|
|
159
|
+
db.run("DELETE FROM networks WHERE network_id = ?1 AND owner_id = ?2", [networkId, userId]);
|
|
160
|
+
return { ok: true };
|
|
161
|
+
}
|
|
162
|
+
|
|
142
163
|
export function createToken(userId: string, name: string, networkId?: string): { ok: boolean; token?: string; token_id?: string; error?: string } {
|
|
143
164
|
const token = generateToken();
|
|
144
165
|
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, renameNetwork, 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,34 @@ 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
|
+
|
|
413
|
+
if (netDetailMatch && req.method === "PUT") {
|
|
414
|
+
const token = req.headers.get("Authorization")?.replace("Bearer ", "") || url.searchParams.get("token");
|
|
415
|
+
if (!token) return withCors(req, Response.json({ ok: false, error: "auth required" }, { status: 401 }));
|
|
416
|
+
const resolved = resolveToken(token);
|
|
417
|
+
if (!resolved) return withCors(req, Response.json({ ok: false, error: "invalid token" }, { status: 401 }));
|
|
418
|
+
try {
|
|
419
|
+
const body = await req.json() as any;
|
|
420
|
+
if (body.name) {
|
|
421
|
+
const result = renameNetwork(resolved.user.user_id, netDetailMatch[1], body.name);
|
|
422
|
+
if (result.ok) logAudit(resolved.user.user_id, resolved.user.username, "network_renamed", "network", netDetailMatch[1], body.name);
|
|
423
|
+
return withCors(req, Response.json(result, { status: result.ok ? 200 : 400 }));
|
|
424
|
+
}
|
|
425
|
+
return withCors(req, Response.json({ ok: false, error: "name required" }, { status: 400 }));
|
|
426
|
+
} catch (e: any) {
|
|
427
|
+
return withCors(req, Response.json({ ok: false, error: e.message }, { status: 400 }));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
403
431
|
// ── REST: health (public, no auth) ──
|
|
404
432
|
if (url.pathname === "/health") {
|
|
405
433
|
const count = db.query<{ cnt: number }, []>("SELECT COUNT(*) as cnt FROM sessions").get();
|