| 82 | } |
| 83 | |
| 84 | export function sessionLogPlugin(): Plugin { |
| 85 | return { |
| 86 | name: "chat-session-log", |
| 87 | configureServer(server) { |
| 88 | server.middlewares.use(async (req, res, next) => { |
| 89 | const url = new URL(req.url ?? "/", "http://localhost"); |
| 90 | |
| 91 | if (url.pathname === "/api/sessions" && req.method === "GET") { |
| 92 | ensureSessionDir(); |
| 93 | res.setHeader("Content-Type", "application/json"); |
| 94 | res.end(JSON.stringify(listSessionSummaries())); |
| 95 | return; |
| 96 | } |
| 97 | |
| 98 | if (url.pathname !== "/api/session") { |
| 99 | next(); |
| 100 | return; |
| 101 | } |
| 102 | |
| 103 | ensureSessionDir(); |
| 104 | |
| 105 | if (req.method === "GET") { |
| 106 | const id = url.searchParams.get("id"); |
| 107 | const filePath = id |
| 108 | ? path.join(SESSION_DIR, `${id}.json`) |
| 109 | : CURRENT_FILE; |
| 110 | |
| 111 | if (!fs.existsSync(filePath)) { |
| 112 | res.statusCode = 204; |
| 113 | res.end(); |
| 114 | return; |
| 115 | } |
| 116 | res.setHeader("Content-Type", "application/json"); |
| 117 | res.end(fs.readFileSync(filePath, "utf8")); |
| 118 | return; |
| 119 | } |
| 120 | |
| 121 | if (req.method === "POST") { |
| 122 | try { |
| 123 | const raw = await readBody(req); |
| 124 | const session = JSON.parse(raw) as { id?: string }; |
| 125 | if (!session?.id) { |
| 126 | res.statusCode = 400; |
| 127 | res.end(JSON.stringify({ error: "session.id required" })); |
| 128 | return; |
| 129 | } |
| 130 | |
| 131 | const payload = JSON.stringify(session, null, 2); |
| 132 | fs.writeFileSync(CURRENT_FILE, payload, "utf8"); |
| 133 | fs.writeFileSync( |
| 134 | path.join(SESSION_DIR, `${session.id}.json`), |
| 135 | payload, |
| 136 | "utf8", |
| 137 | ); |
| 138 | |
| 139 | res.statusCode = 200; |
| 140 | res.setHeader("Content-Type", "application/json"); |
| 141 | res.end(JSON.stringify({ ok: true, path: SESSION_DIR })); |