Cele chybove hlaseni u konektoru i skriptu

U odpovedi 401 nebo 400 je duvod napsany v tele odpovedi sluzby, ne v tom, ze
prislo 401. Dosud se telo zkracovalo na 400 znaku a u overeni konektoru se
zahazovalo cele - zbyla veta "Pristup zamitnut", podle ktere se neda hledat.

- ScriptError nese `request` (metoda a cesta) a `detail` s celou odpovedi
  sluzby, zkracenou az na SCRIPT_ERROR_DETAIL_BYTES (vychozi 8 kB). Chyby jsou
  vzacne, takze objem neroste jako u logu uspesnych kroku
- do detailu jde surove telo, ne prochazene pres JSON.stringify. U chyby chceme
  presne to, co sluzba poslala, vcetne HTML nebo prosteho textu
- u chyby spojeni se pridava i `cause`, u neocekavane vyjimky zasobnik volani
  (mimo produkci, stejne jako u centralniho error handleru)
- overeni konektoru vraci `detail`, `status` i `request`
- cely detail jde i do logu serveru, at je to dohledatelne bez portalu
- do chyby se dava jen cesta, ne cela adresa: v query muze byt tajemstvi
- nova komponenta ErrorDetail: rozbaleni cele odpovedi a tlacitko Kopirovat vse

Overeno: npm run typecheck prochazi na serveru i webu.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
JiriUhlir
2026-08-12 14:38:43 +02:00
co-authored by Claude Opus 5
parent ad56c7f513
commit 3279dd7dac
9 changed files with 306 additions and 70 deletions
+24 -5
View File
@@ -37,10 +37,11 @@ import {
visibleServices,
type Service,
} from '../data/services.js';
import { config } from '../config.js';
import { resolveTarget, serviceBaseUrl } from '../scripts/connections.js';
import { createHttp } from '../scripts/http.js';
import { ScriptError } from '../scripts/types.js';
import { createRedactor, describe } from '../scripts/util.js';
import { createRedactor, describe, truncate } from '../scripts/util.js';
export const connectorsRouter = Router();
@@ -298,18 +299,36 @@ connectorsRouter.post('/:id/test', async (req, res) => {
ok: true,
checked,
status: response.status,
request: { method: 'GET', path },
message: service.verifyPath
? 'Napojení funguje, přístupové údaje jsou platné.'
: 'Služba odpovídá. Přístupové údaje se tímhle neověřily, služba na to nemá čtecí volání.',
});
} catch (err) {
const message =
err instanceof ScriptError ? redact(err.message) : redact(describe(err, 200));
// Cela odpoved sluzby, ne jen "HTTP 401". Duvod je napsany prave v ni.
const isScriptError = err instanceof ScriptError;
const message = isScriptError ? redact(err.message) : redact(describe(err, 400));
const detail = isScriptError
? err.detail
? redact(err.detail)
: undefined
: redact(truncate(String(err instanceof Error ? err.stack ?? err.message : err), config.errorDetailBytes));
setConnectorStatus(connector.id, 'error', message, [tenantId]);
console.warn(`[connectors] test ${connector.id} selhal: ${message}`);
console.warn(
`[connectors] test ${connector.id} selhal: ${message}` + (detail ? `
${detail}` : ''),
);
// Neuspesne overeni neni chyba API, je to vysledek. Proto 200.
return res.json({ ok: false, checked, message });
return res.json({
ok: false,
checked,
message,
...(isScriptError && err.status !== undefined ? { status: err.status } : {}),
request: isScriptError && err.request ? err.request : { method: 'GET', path },
...(detail ? { detail } : {}),
});
} finally {
clearTimeout(timer);
}