@yaebal/panel 0.0.1 → 0.0.2

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/lib/index.test.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
3
  import { Composer, Context } from "@yaebal/core";
4
- import { MemoryPanelStore, panelHandler, recorder } from "./index.js";
4
+ import { MemoryPanelStore, panelHandler, recordOutgoing, recorder } from "./index.js";
5
5
  const noop = async () => { };
6
6
  const entry = (c) => c.toMiddleware();
7
7
  test("MemoryPanelStore records, preserves names, sorts and reads history", () => {
@@ -84,4 +84,325 @@ test("panel send posts via the api and logs an outgoing message", async () => {
84
84
  assert.equal(last?.direction, "out");
85
85
  assert.equal(last?.text, "yo");
86
86
  });
87
+ test("recorder records a media placeholder when a private message carries no text", async () => {
88
+ const store = new MemoryPanelStore();
89
+ const api = {};
90
+ const mw = entry(new Composer().install(recorder(store)));
91
+ const ctx = new Context({
92
+ api,
93
+ update: {
94
+ update_id: 1,
95
+ message: {
96
+ message_id: 1,
97
+ date: 0,
98
+ chat: { id: 7, type: "private" },
99
+ from: { id: 7, is_bot: false, first_name: "Pat" },
100
+ photo: [{ file_id: "x", file_unique_id: "x", width: 1, height: 1 }],
101
+ },
102
+ },
103
+ updateType: "message",
104
+ });
105
+ await mw(ctx, noop);
106
+ assert.equal(store.history(7)[0]?.text, "[photo]");
107
+ });
108
+ test("recorder captures a caption as the message text", async () => {
109
+ const store = new MemoryPanelStore();
110
+ const api = {};
111
+ const mw = entry(new Composer().install(recorder(store)));
112
+ const ctx = new Context({
113
+ api,
114
+ update: {
115
+ update_id: 1,
116
+ message: {
117
+ message_id: 1,
118
+ date: 0,
119
+ chat: { id: 8, type: "private" },
120
+ from: { id: 8, is_bot: false, first_name: "Lee" },
121
+ document: { file_id: "d", file_unique_id: "d" },
122
+ caption: "the report",
123
+ },
124
+ },
125
+ updateType: "message",
126
+ });
127
+ await mw(ctx, noop);
128
+ assert.equal(store.history(8)[0]?.text, "the report");
129
+ });
130
+ test("panel send rejects an empty/missing text with 400", async () => {
131
+ const { handler, sent } = fakePanel();
132
+ const res = await handler(new Request("http://x/api/chats/1/send?token=secret", {
133
+ method: "POST",
134
+ headers: { "content-type": "application/json" },
135
+ body: JSON.stringify({}),
136
+ }));
137
+ assert.equal(res.status, 400);
138
+ assert.deepEqual(sent, []);
139
+ });
140
+ test("panel send forwards whitelisted extras (parse_mode) to sendMessage", async () => {
141
+ const { handler, sent } = fakePanel();
142
+ await handler(new Request("http://x/api/chats/1/send?token=secret", {
143
+ method: "POST",
144
+ headers: { "content-type": "application/json" },
145
+ body: JSON.stringify({ text: "*hi*", parse_mode: "MarkdownV2", bogus: 1 }),
146
+ }));
147
+ assert.deepEqual(sent, [{ chat_id: 1, text: "*hi*", parse_mode: "MarkdownV2" }]);
148
+ });
149
+ test("panel API returns 404 for an unknown path", async () => {
150
+ const { handler } = fakePanel();
151
+ const res = await handler(new Request("http://x/api/nope", { headers: { authorization: "Bearer secret" } }));
152
+ assert.equal(res.status, 404);
153
+ });
154
+ test("CORS: preflight is answered unauthenticated and echoes an allowed origin", async () => {
155
+ const store = new MemoryPanelStore();
156
+ const api = { sendMessage: () => Promise.resolve({}) };
157
+ const handler = panelHandler(api, store, { token: "secret", cors: "https://ops.example" });
158
+ const res = await handler(new Request("http://x/api/chats", {
159
+ method: "OPTIONS",
160
+ headers: { origin: "https://ops.example" },
161
+ }));
162
+ assert.equal(res.status, 204);
163
+ assert.equal(res.headers.get("access-control-allow-origin"), "https://ops.example");
164
+ });
165
+ test("CORS: a disallowed origin gets no allow-origin header", async () => {
166
+ const store = new MemoryPanelStore();
167
+ const api = { sendMessage: () => Promise.resolve({}) };
168
+ const handler = panelHandler(api, store, { token: "secret", cors: "https://ops.example" });
169
+ const res = await handler(new Request("http://x/api/chats?token=secret", {
170
+ headers: { origin: "https://evil.example" },
171
+ }));
172
+ assert.equal(res.headers.get("access-control-allow-origin"), null);
173
+ });
174
+ test("history pagination: limit returns the most recent N, before pages older", () => {
175
+ const s = new MemoryPanelStore();
176
+ for (let i = 1; i <= 5; i++) {
177
+ s.record({ id: 1, name: "@u" }, { direction: "in", text: `m${i}`, date: i });
178
+ }
179
+ const recent = s.history(1, { limit: 2 });
180
+ assert.deepEqual(recent.map((m) => m.text), ["m4", "m5"]);
181
+ const older = s.history(1, { before: 4, limit: 2 });
182
+ assert.deepEqual(older.map((m) => m.text), ["m2", "m3"]);
183
+ });
184
+ test("MemoryPanelStore.subscribe emits a record event and unsubscribes", () => {
185
+ const s = new MemoryPanelStore();
186
+ const seen = [];
187
+ const off = s.subscribe((e) => seen.push(`${e.type}:${e.chatId}:${e.direction}`));
188
+ s.record({ id: 9, name: "@u" }, { direction: "in", text: "hi", date: 1 });
189
+ off();
190
+ s.record({ id: 9, name: "@u" }, { direction: "in", text: "bye", date: 2 });
191
+ assert.deepEqual(seen, ["record:9:in"]);
192
+ });
193
+ test("panel serves the login page at the root WITHOUT a token", async () => {
194
+ const { handler } = fakePanel();
195
+ const res = await handler(new Request("http://x/"));
196
+ assert.equal(res.status, 200);
197
+ assert.match(res.headers.get("content-type") ?? "", /text\/html/);
198
+ const html = await res.text();
199
+ assert.match(html, /authorize/);
200
+ assert.doesNotMatch(html, /__BASE__/); // placeholder was substituted
201
+ });
202
+ test("basePath: routes are matched under the prefix and the UI base is injected", async () => {
203
+ const store = new MemoryPanelStore();
204
+ store.record({ id: 1, name: "@sam" }, { direction: "in", text: "hi", date: 1 });
205
+ const api = { sendMessage: () => Promise.resolve({}) };
206
+ const handler = panelHandler(api, store, { token: "secret", basePath: "/panel" });
207
+ const off = await handler(new Request("http://x/api/chats?token=secret"));
208
+ assert.equal(off.status, 404); // not under the prefix
209
+ const page = await handler(new Request("http://x/panel"));
210
+ assert.equal(page.status, 200);
211
+ assert.match(await page.text(), /BASE = "\/panel"/);
212
+ const chats = await handler(new Request("http://x/panel/api/chats?token=secret"));
213
+ assert.equal(chats.status, 200);
214
+ assert.equal((await chats.json()).length, 1);
215
+ });
216
+ test("rate limit: repeated bad tokens get 429 with Retry-After", async () => {
217
+ const store = new MemoryPanelStore();
218
+ const api = { sendMessage: () => Promise.resolve({}) };
219
+ const handler = panelHandler(api, store, {
220
+ token: "secret",
221
+ rateLimit: { max: 3, windowMs: 60_000 },
222
+ });
223
+ const bad = () => handler(new Request("http://x/api/chats", { headers: { authorization: "Bearer nope" } }));
224
+ for (let i = 0; i < 3; i++)
225
+ assert.equal((await bad()).status, 401);
226
+ const blocked = await bad();
227
+ assert.equal(blocked.status, 429);
228
+ assert.ok(Number(blocked.headers.get("retry-after")) > 0);
229
+ });
230
+ test("SSE stream advertises text/event-stream and forwards a record event", async () => {
231
+ const store = new MemoryPanelStore();
232
+ const api = { sendMessage: () => Promise.resolve({}) };
233
+ const handler = panelHandler(api, store, { token: "secret" });
234
+ const res = await handler(new Request("http://x/api/stream?token=secret"));
235
+ assert.match(res.headers.get("content-type") ?? "", /text\/event-stream/);
236
+ const reader = res.body.getReader();
237
+ await reader.read(); // ": connected"
238
+ store.record({ id: 1, name: "@u" }, { direction: "in", text: "ping", date: 1 });
239
+ const { value } = await reader.read();
240
+ assert.match(new TextDecoder().decode(value), /event: record/);
241
+ await reader.cancel();
242
+ });
243
+ test("recordOutgoing logs bot replies sent outside the panel (private only)", () => {
244
+ const store = new MemoryPanelStore();
245
+ // minimal api fake exposing the `after` hook contract
246
+ let hook;
247
+ const api = { after: (h) => (hook = h) };
248
+ recordOutgoing(api, store);
249
+ // a reply to a private chat → recorded as "out"
250
+ hook?.("sendMessage", { chat: { id: 5, type: "private" }, text: "hey", date: 100 });
251
+ // a group reply → ignored
252
+ hook?.("sendMessage", { chat: { id: -10, type: "group" }, text: "nope", date: 101 });
253
+ // a non-send method → ignored
254
+ hook?.("deleteMessage", { chat: { id: 5, type: "private" } });
255
+ const hist = store.history(5);
256
+ assert.equal(hist.length, 1);
257
+ assert.equal(hist[0]?.direction, "out");
258
+ assert.equal(hist[0]?.text, "hey");
259
+ assert.equal(store.history(-10).length, 0);
260
+ });
261
+ test("panel send does NOT self-record when recordSends is false", async () => {
262
+ const store = new MemoryPanelStore();
263
+ const sent = [];
264
+ const api = {
265
+ sendMessage: (p) => {
266
+ sent.push(p);
267
+ return Promise.resolve({ message_id: 1 });
268
+ },
269
+ };
270
+ const handler = panelHandler(api, store, { token: "secret", recordSends: false });
271
+ await handler(new Request("http://x/api/chats/7/send?token=secret", {
272
+ method: "POST",
273
+ headers: { "content-type": "application/json" },
274
+ body: JSON.stringify({ text: "hi" }),
275
+ }));
276
+ assert.deepEqual(sent, [{ chat_id: 7, text: "hi" }]); // still sent
277
+ assert.equal(store.history(7).length, 0); // but not recorded by the panel
278
+ });
279
+ test("recorder extracts a photo attachment + caption from an incoming message", async () => {
280
+ const store = new MemoryPanelStore();
281
+ const api = {};
282
+ const mw = entry(new Composer().install(recorder(store)));
283
+ const ctx = new Context({
284
+ api,
285
+ update: {
286
+ update_id: 1,
287
+ message: {
288
+ message_id: 1,
289
+ date: 0,
290
+ chat: { id: 7, type: "private" },
291
+ from: { id: 7, is_bot: false, first_name: "Pat" },
292
+ photo: [
293
+ { file_id: "small", file_unique_id: "s", width: 90, height: 90 },
294
+ { file_id: "big", file_unique_id: "b", width: 1280, height: 1280 },
295
+ ],
296
+ media_group_id: "AG123",
297
+ caption: "look!",
298
+ },
299
+ },
300
+ updateType: "message",
301
+ });
302
+ await mw(ctx, noop);
303
+ const m = store.history(7)[0];
304
+ assert.equal(m?.text, "look!");
305
+ assert.deepEqual(m?.attachments, [{ type: "photo", fileId: "big" }]); // largest size
306
+ assert.equal(m?.mediaGroupId, "AG123");
307
+ });
308
+ test("recorder extracts a document with name + mime", async () => {
309
+ const store = new MemoryPanelStore();
310
+ const api = {};
311
+ const mw = entry(new Composer().install(recorder(store)));
312
+ const ctx = new Context({
313
+ api,
314
+ update: {
315
+ update_id: 1,
316
+ message: {
317
+ message_id: 1,
318
+ date: 0,
319
+ chat: { id: 8, type: "private" },
320
+ from: { id: 8, is_bot: false, first_name: "Lee" },
321
+ document: { file_id: "doc1", file_unique_id: "d", file_name: "report.pdf", mime_type: "application/pdf" },
322
+ },
323
+ },
324
+ updateType: "message",
325
+ });
326
+ await mw(ctx, noop);
327
+ const m = store.history(8)[0];
328
+ assert.equal(m?.text, "[document]"); // placeholder preview, no caption
329
+ assert.deepEqual(m?.attachments, [
330
+ { type: "document", fileId: "doc1", fileName: "report.pdf", mimeType: "application/pdf" },
331
+ ]);
332
+ });
333
+ test("GET /api/file proxies telegram bytes via getFile + fileUrl", async () => {
334
+ const store = new MemoryPanelStore();
335
+ const calls = [];
336
+ const api = {
337
+ sendMessage: () => Promise.resolve({}),
338
+ call: (method, params) => {
339
+ calls.push(`${method}:${params?.file_id}`);
340
+ return Promise.resolve({ file_path: "photos/x.jpg" });
341
+ },
342
+ fileUrl: (p) => `https://files.test/${p}`,
343
+ };
344
+ // stub fetch for the upstream download
345
+ const realFetch = globalThis.fetch;
346
+ globalThis.fetch = (async (u) => {
347
+ assert.equal(u, "https://files.test/photos/x.jpg");
348
+ return new Response(new Uint8Array([1, 2, 3]), { headers: { "content-type": "image/jpeg" } });
349
+ });
350
+ try {
351
+ const handler = panelHandler(api, store, { token: "secret" });
352
+ const res = await handler(new Request("http://x/api/file?id=ABC&token=secret"));
353
+ assert.equal(res.status, 200);
354
+ assert.equal(res.headers.get("content-type"), "image/jpeg");
355
+ assert.deepEqual([...new Uint8Array(await res.arrayBuffer())], [1, 2, 3]);
356
+ assert.deepEqual(calls, ["getFile:ABC"]);
357
+ }
358
+ finally {
359
+ globalThis.fetch = realFetch;
360
+ }
361
+ });
362
+ test("GET /api/file returns 501 when the api can't proxy", async () => {
363
+ const { handler } = fakePanel(); // fake api has no call/fileUrl
364
+ const res = await handler(new Request("http://x/api/file?id=ABC&token=secret"));
365
+ assert.equal(res.status, 501);
366
+ });
367
+ test("multipart send uploads a file via the inferred send method", async () => {
368
+ const store = new MemoryPanelStore();
369
+ const calls = [];
370
+ const api = {
371
+ sendMessage: () => Promise.resolve({}),
372
+ call: (method, params) => {
373
+ calls.push({ method, params: params ?? {} });
374
+ return Promise.resolve({
375
+ chat: { id: 1, type: "private" },
376
+ date: 5,
377
+ photo: [{ file_id: "up1" }],
378
+ });
379
+ },
380
+ };
381
+ const handler = panelHandler(api, store, { token: "secret" });
382
+ const fd = new FormData();
383
+ fd.append("file", new Blob([new Uint8Array([9, 9])], { type: "image/png" }), "pic.png");
384
+ fd.append("caption", "hi");
385
+ const res = await handler(new Request("http://x/api/chats/1/send?token=secret", { method: "POST", body: fd }));
386
+ assert.equal(res.status, 200);
387
+ assert.equal(calls[0]?.method, "sendPhoto"); // inferred from image/png
388
+ assert.equal(calls[0]?.params.caption, "hi");
389
+ // recorded as an outgoing photo
390
+ const m = store.history(1).at(-1);
391
+ assert.equal(m?.direction, "out");
392
+ assert.deepEqual(m?.attachments, [{ type: "photo", fileId: "up1" }]);
393
+ });
394
+ test("recordOutgoing captures a sendMediaGroup array result", () => {
395
+ const store = new MemoryPanelStore();
396
+ let hook;
397
+ const api = { after: (h) => (hook = h) };
398
+ recordOutgoing(api, store);
399
+ hook?.("sendMediaGroup", [
400
+ { chat: { id: 3, type: "private" }, date: 1, media_group_id: "G", photo: [{ file_id: "a" }] },
401
+ { chat: { id: 3, type: "private" }, date: 1, media_group_id: "G", photo: [{ file_id: "b" }] },
402
+ ]);
403
+ const hist = store.history(3);
404
+ assert.equal(hist.length, 2);
405
+ assert.equal(hist[0]?.mediaGroupId, "G");
406
+ assert.deepEqual(hist[1]?.attachments, [{ type: "photo", fileId: "b" }]);
407
+ });
87
408
  //# sourceMappingURL=index.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- /** the operator panel ui — a single static page that talks to the panel api. */
2
- export declare const PANEL_HTML = "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>yaebal panel</title>\n<style>\n :root { color-scheme: light dark; --bg:#0f1115; --panel:#171a21; --line:#252a33; --muted:#8b93a1; --accent:#229ED9; --text:#e6e8eb; }\n * { box-sizing: border-box; }\n body { margin:0; font:14px/1.5 system-ui,sans-serif; background:var(--bg); color:var(--text); height:100vh; display:flex; }\n #chats { width:280px; border-right:1px solid var(--line); overflow-y:auto; flex:none; }\n #chats h1 { font-size:13px; color:var(--muted); padding:14px 16px; margin:0; letter-spacing:.5px; text-transform:lowercase; }\n .chat { padding:10px 16px; border-bottom:1px solid var(--line); cursor:pointer; }\n .chat:hover, .chat.on { background:var(--panel); }\n .chat .n { font-weight:500; }\n .chat .l { color:var(--muted); font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n #main { flex:1; display:flex; flex-direction:column; min-width:0; }\n #log { flex:1; overflow-y:auto; padding:16px; display:flex; flex-direction:column; gap:8px; }\n .msg { max-width:70%; padding:8px 12px; border-radius:12px; white-space:pre-wrap; word-break:break-word; }\n .msg.in { background:var(--panel); align-self:flex-start; }\n .msg.out { background:var(--accent); color:#fff; align-self:flex-end; }\n #composer { display:flex; gap:8px; padding:12px; border-top:1px solid var(--line); }\n #composer input { flex:1; background:var(--panel); border:1px solid var(--line); color:var(--text); border-radius:8px; padding:9px 12px; font:inherit; }\n #composer button { background:var(--accent); color:#fff; border:0; border-radius:8px; padding:0 16px; cursor:pointer; font:inherit; }\n #empty { margin:auto; color:var(--muted); }\n</style>\n</head>\n<body>\n<div id=\"chats\"><h1>chats</h1></div>\n<div id=\"main\"><div id=\"empty\">select a chat</div></div>\n<script>\nconst token = new URLSearchParams(location.search).get(\"token\") || \"\";\nconst api = (p, opt = {}) => fetch(p, { ...opt, headers: { ...(opt.headers||{}), authorization: \"Bearer \" + token } });\nlet active = null;\nconst el = (t, c, x) => { const e = document.createElement(t); if (c) e.className = c; if (x != null) e.textContent = x; return e; };\n\nasync function loadChats() {\n const chats = await (await api(\"/api/chats\")).json();\n const box = document.getElementById(\"chats\");\n box.querySelectorAll(\".chat\").forEach(n => n.remove());\n for (const c of chats) {\n const d = el(\"div\", \"chat\" + (c.id === active ? \" on\" : \"\"));\n d.append(el(\"div\", \"n\", c.name), el(\"div\", \"l\", c.lastText));\n d.onclick = () => openChat(c.id);\n box.append(d);\n }\n}\nasync function openChat(id) {\n active = id;\n await loadChats();\n const msgs = await (await api(\"/api/chats/\" + id)).json();\n const main = document.getElementById(\"main\");\n main.innerHTML = \"\";\n const log = el(\"div\"); log.id = \"log\";\n for (const m of msgs) log.append(el(\"div\", \"msg \" + m.direction, m.text));\n const form = el(\"form\"); form.id = \"composer\";\n const input = el(\"input\"); input.placeholder = \"reply\u2026\"; input.autocomplete = \"off\";\n const btn = el(\"button\", null, \"send\"); btn.type = \"submit\";\n form.append(input, btn);\n form.onsubmit = async (e) => {\n e.preventDefault();\n const text = input.value.trim(); if (!text) return;\n input.value = \"\";\n await api(\"/api/chats/\" + id + \"/send\", { method:\"POST\", headers:{\"content-type\":\"application/json\"}, body: JSON.stringify({ text }) });\n openChat(id);\n };\n main.append(log, form);\n log.scrollTop = log.scrollHeight;\n}\nloadChats();\nsetInterval(() => (active ? openChat(active) : loadChats()), 4000);\n</script>\n</body>\n</html>";
1
+ /** the operator panel ui — a single static page: token login, then the live chat view. */
2
+ export declare const PANEL_HTML = "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>yaebal panel</title>\n<style>\n :root { color-scheme: light dark; --bg:#0f1115; --panel:#171a21; --line:#252a33; --muted:#8b93a1; --accent:#229ED9; --accent-2:#1b87ba; --text:#e6e8eb; --danger:#e5484d; }\n * { box-sizing: border-box; }\n body { margin:0; font:14px/1.5 system-ui,-apple-system,sans-serif; background:var(--bg); color:var(--text); height:100vh; display:flex; }\n\n /* ---- login ---- */\n #login { margin:auto; width:300px; display:flex; flex-direction:column; gap:14px; padding:24px; }\n #login .brand { text-align:center; font-size:20px; font-weight:600; letter-spacing:-.2px; }\n #login .brand b { color:var(--accent); }\n #login .sub { text-align:center; color:var(--muted); font-size:12px; margin-top:-8px; }\n #login input, #login button { width:100%; height:44px; border-radius:10px; font:inherit; padding:0 14px; }\n #login input { background:var(--panel); border:1px solid var(--line); color:var(--text); text-align:center; }\n #login input:focus { outline:none; border-color:var(--accent); }\n #login button { background:var(--accent); color:#fff; border:0; cursor:pointer; font-weight:600; transition:background .15s; }\n #login button:hover { background:var(--accent-2); }\n #login button:disabled { opacity:.6; cursor:default; }\n #login .err { color:var(--danger); font-size:12px; text-align:center; min-height:16px; }\n\n /* ---- app ---- */\n #app { display:none; flex:1; }\n body.authed #login { display:none; }\n body.authed #app { display:flex; }\n #chats { width:280px; border-right:1px solid var(--line); overflow-y:auto; flex:none; display:flex; flex-direction:column; }\n #chats .top { display:flex; align-items:center; justify-content:space-between; padding:14px 16px; }\n #chats .top h1 { font-size:13px; color:var(--muted); margin:0; letter-spacing:.5px; text-transform:lowercase; }\n #chats .top button { background:none; border:0; color:var(--muted); cursor:pointer; font:inherit; font-size:12px; }\n #chats .top button:hover { color:var(--text); }\n .chat { padding:10px 16px; border-top:1px solid var(--line); cursor:pointer; }\n .chat:hover, .chat.on { background:var(--panel); }\n .chat .n { font-weight:500; }\n .chat .l { color:var(--muted); font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n #main { flex:1; display:flex; flex-direction:column; min-width:0; }\n #log { flex:1; overflow-y:auto; padding:16px; display:flex; flex-direction:column; gap:8px; }\n #log .more { align-self:center; background:none; border:1px solid var(--line); color:var(--muted); border-radius:999px; padding:4px 14px; cursor:pointer; font:inherit; font-size:12px; }\n .msg { max-width:70%; padding:8px 12px; border-radius:12px; white-space:pre-wrap; word-break:break-word; }\n .msg.in { background:var(--panel); align-self:flex-start; }\n .msg.out { background:var(--accent); color:#fff; align-self:flex-end; }\n .msg img, .msg video { max-width:280px; max-height:320px; border-radius:8px; display:block; }\n .msg audio { width:260px; display:block; }\n .msg .cap { margin-top:6px; }\n .msg .media + .media { margin-top:6px; }\n .msg .doc { display:inline-flex; align-items:center; gap:6px; color:inherit; text-decoration:none; border-bottom:1px dotted currentColor; }\n .msg.album { display:flex; flex-wrap:wrap; gap:4px; max-width:300px; }\n .msg.album img, .msg.album video { max-width:140px; max-height:140px; margin:0; }\n .msg.album .cap { flex-basis:100%; }\n #composer { display:flex; gap:8px; padding:12px; border-top:1px solid var(--line); }\n #composer input.text { flex:1; background:var(--panel); border:1px solid var(--line); color:var(--text); border-radius:8px; padding:9px 12px; font:inherit; }\n #composer button { background:var(--accent); color:#fff; border:0; border-radius:8px; padding:0 16px; cursor:pointer; font:inherit; }\n #composer .attach { background:var(--panel); border:1px solid var(--line); color:var(--muted); padding:0 12px; }\n #composer .attach:hover { color:var(--text); }\n #empty { margin:auto; color:var(--muted); }\n</style>\n</head>\n<body>\n<form id=\"login\">\n <div class=\"brand\"><b>@yaebal</b>/panel</div>\n <div class=\"sub\">operator panel</div>\n <input id=\"token\" type=\"password\" placeholder=\"access token\" autocomplete=\"off\" autofocus />\n <button id=\"go\" type=\"submit\">authorize</button>\n <div class=\"err\" id=\"err\"></div>\n</form>\n\n<div id=\"app\">\n <div id=\"chats\"><div class=\"top\"><h1>chats</h1><button id=\"logout\" type=\"button\">log out</button></div></div>\n <div id=\"main\"><div id=\"empty\">select a chat</div></div>\n</div>\n\n<script>\nconst BASE = \"__BASE__\";\nconst KEY = \"yaebal-panel-token\" + BASE;\nlet token = sessionStorage.getItem(KEY) || \"\";\nlet active = null, oldest = null, es = null;\n\nconst el = (t, c, x) => { const e = document.createElement(t); if (c) e.className = c; if (x != null) e.textContent = x; return e; };\nconst api = (p, opt = {}) => fetch(BASE + p, { ...opt, headers: { ...(opt.headers||{}), authorization: \"Bearer \" + token } });\n\n/* ---- auth ---- */\nconst login = document.getElementById(\"login\");\nlogin.onsubmit = async (e) => {\n e.preventDefault();\n const go = document.getElementById(\"go\"), err = document.getElementById(\"err\");\n token = document.getElementById(\"token\").value.trim();\n if (!token) return;\n go.disabled = true; err.textContent = \"\";\n const res = await api(\"/api/chats\").catch(() => null);\n go.disabled = false;\n if (!res || !res.ok) { err.textContent = \"invalid token\"; return; }\n sessionStorage.setItem(KEY, token);\n enter();\n};\ndocument.getElementById(\"logout\").onclick = () => {\n sessionStorage.removeItem(KEY); token = \"\"; active = null;\n if (es) { es.close(); es = null; }\n document.body.classList.remove(\"authed\");\n document.getElementById(\"token\").value = \"\";\n};\n\nfunction enter() {\n document.body.classList.add(\"authed\");\n loadChats();\n openStream();\n}\n\n/* ---- realtime: instant via SSE, with a slow polling safety net ---- */\nfunction openStream() {\n if (es || !window.EventSource) return;\n es = new EventSource(BASE + \"/api/stream?token=\" + encodeURIComponent(token));\n es.addEventListener(\"record\", (ev) => {\n const e = JSON.parse(ev.data);\n if (active && e.chatId === active) openChat(active, true);\n loadChats();\n });\n es.onerror = () => {}; // EventSource auto-reconnects\n}\nsetInterval(() => { if (token) (active ? openChat(active, true) : loadChats()); }, 8000);\n\n/* ---- chats ---- */\nasync function loadChats() {\n const res = await api(\"/api/chats\"); if (!res.ok) return;\n const chats = await res.json();\n const box = document.getElementById(\"chats\");\n box.querySelectorAll(\".chat\").forEach(n => n.remove());\n for (const c of chats) {\n const d = el(\"div\", \"chat\" + (c.id === active ? \" on\" : \"\"));\n d.append(el(\"div\", \"n\", c.name), el(\"div\", \"l\", c.lastText));\n d.onclick = () => openChat(c.id);\n box.append(d);\n }\n}\n\n/* ---- media rendering ---- */\nconst fileSrc = (att) => BASE + \"/api/file?id=\" + encodeURIComponent(att.fileId) + \"&token=\" + encodeURIComponent(token);\nconst isPlaceholder = (t) => /^[[a-z_]+]$/.test(t);\n\nfunction attEl(att) {\n const src = fileSrc(att);\n if (att.type === \"photo\" || att.type === \"sticker\") { const i = el(\"img\", \"media\"); i.src = src; i.loading = \"lazy\"; return i; }\n if (att.type === \"video\" || att.type === \"animation\" || att.type === \"video_note\") { const v = el(\"video\", \"media\"); v.src = src; v.controls = true; return v; }\n if (att.type === \"voice\" || att.type === \"audio\") { const a = el(\"audio\", \"media\"); a.src = src; a.controls = true; return a; }\n const link = el(\"a\", \"media doc\", \"\uD83D\uDCCE \" + (att.fileName || att.type)); link.href = src; link.target = \"_blank\"; return link;\n}\n\nfunction bubble(m) {\n const b = el(\"div\", \"msg \" + m.direction);\n const atts = m.attachments || [];\n for (const a of atts) b.append(attEl(a));\n if (m.text && !(atts.length && isPlaceholder(m.text))) b.append(el(\"div\", atts.length ? \"cap\" : null, m.text));\n return b;\n}\n\n/* merge consecutive messages sharing a media_group_id into one album bubble */\nfunction renderMsgs(msgs) {\n const out = [];\n let group = null, groupId = null;\n for (const m of msgs) {\n if (m.mediaGroupId && m.mediaGroupId === groupId && group) {\n for (const a of m.attachments || []) group.insertBefore(attEl(a), group.querySelector(\".cap\"));\n if (m.text && !isPlaceholder(m.text)) group.append(el(\"div\", \"cap\", m.text));\n continue;\n }\n const b = bubble(m);\n if (m.mediaGroupId) { b.classList.add(\"album\"); group = b; groupId = m.mediaGroupId; }\n else { group = null; groupId = null; }\n out.push(b);\n }\n return out;\n}\n\nasync function openChat(id, keepScroll) {\n active = id;\n if (!keepScroll) loadChats();\n const res = await api(\"/api/chats/\" + id + \"?limit=200\"); if (!res.ok) return;\n const msgs = await res.json();\n oldest = msgs.length ? msgs[0].date : null;\n\n const main = document.getElementById(\"main\");\n const prevTop = keepScroll ? (main.querySelector(\"#log\")?.scrollTop ?? null) : null;\n main.innerHTML = \"\";\n\n const log = el(\"div\"); log.id = \"log\";\n if (msgs.length >= 200) {\n const more = el(\"button\", \"more\", \"load earlier\"); more.onclick = () => loadEarlier(id, log);\n log.append(more);\n }\n for (const b of renderMsgs(msgs)) log.append(b);\n\n const form = el(\"form\"); form.id = \"composer\";\n const fileInput = el(\"input\"); fileInput.type = \"file\"; fileInput.style.display = \"none\";\n const attach = el(\"button\", \"attach\", \"\uD83D\uDCCE\"); attach.type = \"button\"; attach.title = \"send a file\";\n attach.onclick = () => fileInput.click();\n const input = el(\"input\", \"text\"); input.placeholder = \"reply\u2026\"; input.autocomplete = \"off\";\n const btn = el(\"button\", null, \"send\"); btn.type = \"submit\";\n form.append(attach, fileInput, input, btn);\n\n fileInput.onchange = async () => {\n const file = fileInput.files && fileInput.files[0]; if (!file) return;\n const fd = new FormData(); fd.append(\"file\", file);\n if (input.value.trim()) fd.append(\"caption\", input.value.trim());\n input.value = \"\"; fileInput.value = \"\";\n await api(\"/api/chats/\" + id + \"/send\", { method: \"POST\", body: fd }); // browser sets multipart boundary\n openChat(id);\n };\n form.onsubmit = async (e) => {\n e.preventDefault();\n const text = input.value.trim(); if (!text) return;\n input.value = \"\";\n await api(\"/api/chats/\" + id + \"/send\", { method:\"POST\", headers:{\"content-type\":\"application/json\"}, body: JSON.stringify({ text }) });\n openChat(id);\n };\n main.append(log, form);\n log.scrollTop = prevTop != null ? prevTop : log.scrollHeight;\n}\n\nasync function loadEarlier(id, log) {\n if (oldest == null) return;\n const res = await api(\"/api/chats/\" + id + \"?limit=200&before=\" + oldest); if (!res.ok) return;\n const older = await res.json();\n if (!older.length) { log.querySelector(\".more\")?.remove(); return; }\n oldest = older[0].date;\n const anchor = log.querySelector(\".more\")?.nextSibling ?? log.firstChild;\n const frag = document.createDocumentFragment();\n if (older.length >= 200) { const more = el(\"button\", \"more\", \"load earlier\"); more.onclick = () => loadEarlier(id, log); frag.append(more); }\n for (const b of renderMsgs(older)) frag.append(b);\n log.querySelector(\".more\")?.remove();\n log.insertBefore(frag, anchor);\n}\n\nif (token) enter();\n</script>\n</body>\n</html>";
3
3
  //# sourceMappingURL=panel-html.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"panel-html.d.ts","sourceRoot":"","sources":["../src/panel-html.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,eAAO,MAAM,UAAU,uxHAyEf,CAAC"}
1
+ {"version":3,"file":"panel-html.d.ts","sourceRoot":"","sources":["../src/panel-html.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,eAAO,MAAM,UAAU,+pXA4Of,CAAC"}