kingkont 0.18.12 → 0.18.13

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/main.js CHANGED
@@ -273,12 +273,26 @@ ipcMain.handle('chatium:status', async () => {
273
273
  const base = s?.chatium?.base || CHATIUM_BASE;
274
274
  if (!token) return { connected: false };
275
275
  try {
276
- const r = await fetch(`${base}/app/spaces/server/api/auth~me`, {
277
- headers: { 'Authorization': `Bearer ${token}` },
278
- });
276
+ const url = `${base}/app/spaces/server/api/auth~me`;
277
+ const r = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } });
278
+ const rawText = await r.text();
279
+ let me; try { me = JSON.parse(rawText); } catch { me = null; }
280
+ // Диагностика: логируем что Chatium вообще отдаёт. Юзер жалуется
281
+ // что displayName/email не показываются — нужно увидеть какие
282
+ // поля приходят в реальности.
283
+ console.log(`[chatium:status] ${r.status} ${url}`);
284
+ console.log(`[chatium:status] response keys: ${me ? Object.keys(me).join(', ') : '(non-json)'}`);
285
+ console.log(`[chatium:status] response body: ${rawText.slice(0, 800)}`);
279
286
  if (r.ok) {
280
- const me = await r.json().catch(() => ({}));
281
- return { connected: true, ...me, base };
287
+ // _allKeys и _raw добавлены для UI-debug — renderer покажет их
288
+ // в console если displayName/email/login пусто.
289
+ return {
290
+ connected: true,
291
+ ...(me || {}),
292
+ base,
293
+ _allKeys: me ? Object.keys(me) : [],
294
+ _raw: rawText.slice(0, 800),
295
+ };
282
296
  }
283
297
  if (r.status === 401) {
284
298
  // Токен протух/отозван — чистим.
@@ -287,8 +301,9 @@ ipcMain.handle('chatium:status', async () => {
287
301
  writeSettings(next);
288
302
  return { connected: false, reason: 'expired' };
289
303
  }
290
- return { connected: false, reason: `http_${r.status}` };
304
+ return { connected: false, reason: `http_${r.status}`, _raw: rawText.slice(0, 400) };
291
305
  } catch (e) {
306
+ console.warn('[chatium:status] network error:', e?.message || e);
292
307
  return { connected: false, reason: 'network_error', error: String(e?.message || e) };
293
308
  }
294
309
  });
@@ -296,18 +311,43 @@ ipcMain.handle('chatium:status', async () => {
296
311
  function runChatiumLoginFlow() {
297
312
  return new Promise((resolveOk, rejectErr) => {
298
313
  const state = crypto.randomBytes(16).toString('hex');
314
+ // Кэш отрендеренной success-страницы: после первого успешного /cb
315
+ // ВСЕ следующие запросы (refresh, navigation back, favicon retry,
316
+ // Chatium повторно редиректит и т.д.) отдают ту же страницу.
317
+ // Иначе юзер мог увидеть «localhost не грузится» если refresh'нул
318
+ // вкладку после автозакрытия server'а. Listener живёт ещё 30s
319
+ // после успеха для этих случаев.
320
+ let cachedSuccessPage = null;
321
+ let alreadyResolved = false;
299
322
  const server = http.createServer((req, res) => {
300
323
  const url = new URL(req.url, `http://localhost`);
324
+ console.log(`[chatium-login] ← ${req.method} ${req.url}`);
325
+ // Уже зарезолвили — отдаём ту же success-страницу повторно
326
+ // (юзер refresh'нул, или Chatium шлёт callback дважды).
327
+ if (alreadyResolved && cachedSuccessPage) {
328
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
329
+ res.end(cachedSuccessPage);
330
+ return;
331
+ }
332
+ if (url.pathname === '/favicon.ico') {
333
+ res.writeHead(204); res.end();
334
+ return;
335
+ }
301
336
  if (url.pathname !== '/cb') {
302
- res.writeHead(404); res.end('not found');
337
+ console.log(`[chatium-login] 404 (unexpected path): ${url.pathname}`);
338
+ res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
339
+ res.end('Not found. Ожидался /cb от Chatium-callback.');
303
340
  return;
304
341
  }
305
342
  const token = url.searchParams.get('token');
306
343
  const recvState = url.searchParams.get('state');
344
+ const allParams = Array.from(url.searchParams.keys());
345
+ console.log(`[chatium-login] callback params: ${allParams.join(', ')}`);
307
346
 
308
347
  if (!token || recvState !== state) {
348
+ console.warn(`[chatium-login] BAD callback: token=${!!token} stateMatch=${recvState === state}`);
309
349
  res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
310
- res.end(authResultPage('error', 'Авторизация не удалась (state mismatch или токен пуст). Попробуйте снова.'));
350
+ res.end(authResultPage('error', `Авторизация не удалась. token=${token ? 'есть' : 'нет'}, state=${recvState === state ? 'ok' : 'mismatch'}. Попробуйте снова.`));
311
351
  cleanup();
312
352
  rejectErr(new Error('State mismatch или token пуст'));
313
353
  return;
@@ -318,12 +358,25 @@ function runChatiumLoginFlow() {
318
358
  fetch(`${CHATIUM_BASE}/app/spaces/server/api/auth~me`, {
319
359
  headers: { 'Authorization': `Bearer ${token}` },
320
360
  })
321
- .then(r => r.ok ? r.json() : null)
322
- .catch(() => null)
323
- .then(me => {
361
+ .then(r => r.text().then(t => ({ ok: r.ok, status: r.status, text: t })))
362
+ .catch(e => ({ ok: false, status: 0, text: '', err: e?.message || String(e) }))
363
+ .then(({ ok, status, text, err }) => {
364
+ let me = null;
365
+ try { me = JSON.parse(text); } catch {}
366
+ console.log(`[chatium-login] /me → ${status} keys=${me ? Object.keys(me).join(',') : '(non-json)'}`);
367
+ if (err) console.warn(`[chatium-login] /me fetch failed: ${err}`);
368
+ cachedSuccessPage = authResultPage('ok', 'Готово! Можно закрыть эту вкладку и вернуться в приложение.');
369
+ alreadyResolved = true;
324
370
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
325
- res.end(authResultPage('ok', 'Готово! Можно закрыть эту вкладку и вернуться в приложение.'));
326
- cleanup();
371
+ res.end(cachedSuccessPage);
372
+ // НЕ закрываем server сразу — даём юзеру 30s на refresh / повторный
373
+ // hit (Chatium иногда шлёт callback дважды; или юзер случайно
374
+ // нажал refresh на этой вкладке).
375
+ if (timeoutId) clearTimeout(timeoutId);
376
+ timeoutId = setTimeout(() => {
377
+ console.log('[chatium-login] graceful close after 30s grace period');
378
+ cleanup();
379
+ }, 30 * 1000);
327
380
  resolveOk({
328
381
  token,
329
382
  userId: me?.userId || null,
@@ -342,6 +395,7 @@ function runChatiumLoginFlow() {
342
395
  }
343
396
 
344
397
  server.on('error', (err) => {
398
+ console.warn('[chatium-login] server error:', err.message);
345
399
  cleanup();
346
400
  rejectErr(err);
347
401
  });
@@ -349,12 +403,14 @@ function runChatiumLoginFlow() {
349
403
  server.listen(0, '127.0.0.1', () => {
350
404
  const addr = server.address();
351
405
  const callback = `http://localhost:${addr.port}/cb`;
406
+ console.log(`[chatium-login] listener up on ${callback}`);
352
407
  // На стороне Chatium роут авторизации привязан к корню workspace (/),
353
408
  // т.е. /app/spaces/server. После успеха он редиректит на наш callback с token.
354
409
  const url = new URL(`${CHATIUM_BASE}/app/spaces/server`);
355
410
  url.searchParams.set('callback', callback);
356
411
  url.searchParams.set('state', state);
357
412
  url.searchParams.set('app', 'KingKont');
413
+ console.log(`[chatium-login] opening browser → ${url.toString()}`);
358
414
 
359
415
  shell.openExternal(url.toString()).catch((e) => {
360
416
  cleanup();
@@ -362,6 +418,7 @@ function runChatiumLoginFlow() {
362
418
  });
363
419
 
364
420
  timeoutId = setTimeout(() => {
421
+ console.warn('[chatium-login] timeout 5min — abort');
365
422
  cleanup();
366
423
  rejectErr(new Error('Таймаут: авторизация не завершена за 5 минут'));
367
424
  }, CHATIUM_AUTH_TIMEOUT_MS);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.18.12",
3
+ "version": "0.18.13",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
package/renderer/board.js CHANGED
@@ -216,21 +216,42 @@ async function renderWelcomeIdentity() {
216
216
  let status = null;
217
217
  try { status = await window.appChatium?.status?.(); } catch {}
218
218
  if (status?.connected) {
219
- // Приоритет имени: displayName (UI Chatium)confirmedEmail
220
- // email loginfullName name → userId.
221
- const name = status.displayName || status.confirmedEmail || status.email
222
- || status.login || status.fullName || status.name
219
+ // Приоритет имени: displayName namefullName login → confirmedEmail
220
+ // → emailuser.* (если nested) → userId. Раньше displayName был
221
+ // first, но Chatium может возвращать поле под другим именем —
222
+ // проверяем все известные варианты + nested user-объект.
223
+ const u = status.user || status.profile || status.account || {};
224
+ const name = status.displayName || status.name || status.fullName
225
+ || status.login || status.username || status.userName
226
+ || status.confirmedEmail || status.email
227
+ || u.displayName || u.name || u.fullName || u.login || u.email
223
228
  || status.userId || 'KingKont';
224
229
  const sub = status.userId && status.userId !== name ? `· ${status.userId.slice(0, 8)}` : '';
225
- // Диагностика: если ничего кроме userId не пришло лог в консоль.
226
- if (!status.displayName && !status.confirmedEmail && !status.email) {
227
- console.log('[chat-identity] available fields:', status, 'allKeys:', status._allKeys);
230
+ // Диагностика: если ни одного «человеческого» поля не нашлось
231
+ // громкий лог в консоль с полным дампом, чтобы видеть что прислал
232
+ // сервер (см. main.js [chatium:status] логи тоже).
233
+ const noHumanField = !status.displayName && !status.name && !status.fullName
234
+ && !status.login && !status.confirmedEmail && !status.email
235
+ && !u.displayName && !u.name && !u.email;
236
+ if (noHumanField) {
237
+ console.warn('[chat-identity] No human-readable name field. Status object:', status);
238
+ console.warn('[chat-identity] _allKeys:', status._allKeys);
239
+ console.warn('[chat-identity] _raw:', status._raw);
228
240
  }
229
241
  wrap.innerHTML = `
230
242
  <span style="color:#5c5; font-size:13px; line-height:1;">●</span>
231
243
  <span class="who">${escapeHtml(name)}</span>
232
244
  <span class="who-sub">${escapeHtml(sub)}</span>
233
245
  `;
246
+ // Если имя не найдено — добавляем visible debug-pill с available keys,
247
+ // чтобы юзер мог тебе показать что отдаёт Chatium без копания в консоли.
248
+ if (noHumanField && Array.isArray(status._allKeys) && status._allKeys.length) {
249
+ const dbg = document.createElement('span');
250
+ dbg.style.cssText = 'background:#3a2a4a; color:#dcb; font-size:10px; padding:2px 6px; border-radius:4px; font-family:ui-monospace,monospace; cursor:help;';
251
+ dbg.textContent = `keys: ${status._allKeys.join(',').slice(0, 60)}`;
252
+ dbg.title = `Полный ответ:\n${status._raw || '(пусто)'}\n\nИ скопируй это сообщение разработчику.`;
253
+ wrap.appendChild(dbg);
254
+ }
234
255
  const logoutBtn = document.createElement('button');
235
256
  logoutBtn.textContent = 'Выйти';
236
257
  logoutBtn.title = 'Logout из KingKont';