Skripty konektoru: vykonna cast s manifestem a kontrolou parametru

Konektory dostaly vykonnou cast. Jeden skript je jeden soubor, ktery nese
manifest (vstupni a vystupni parametry) i kod. Diky manifestu s nim umi
pracovat strom automatizace, aniz by o kodu cokoliv vedel.

Soubory jsou zamerne obycejny JavaScript, ne TypeScript. TypeScript by se
musel prelozit a to je presne to otaceni, ktere tady nema byt. Registr
sleduje cas zmeny souboru, takze uprava v portalu, rucni uprava souboru
i novy soubor ve slozce funguji stejne a bez restartu.

Pridano:
- scripts/ se skripty konektoru, nazev souboru je zaroven ID operace
- kontrola vstupu i vystupu proti manifestu, jedna funkce pro obe strany.
  Chybejici povinny vystup je chyba skriptu, ne uzivatele - jinak by strom
  veril parametru, ktery nikdy nedosel
- ctx predavany skriptu: http nad adresou napojeni, util, log, config,
  idempotencyKey, fail a retry. Skript nedostane pristupove udaje
- rozliseni opakovatelne a koncove chyby. Runner nikdy nevyhodi vyjimku,
  vzdy vraci vysledek vcetne retryable
- redakce tajnych hodnot pred zapisem do logu. Cizi API rado vraci prijaty
  token v chybove zprave a log ticketu vidi klient
- napojeni z environment variables vcetne iDokladu
- sest ukazkovych skriptu pro iDoklad proti skutecnemu API sluzby
  services.csbot.cz/apps/idoklad, kazdy na jiny vzor
- stranka /dashboard/skripty: seznam, manifest, editor, zkusebni spusteni.
  Formular testu se sklada z manifestu, nepise se pro kazdy skript
- endpointy /api/dashboard/scripts vcetne Swaggeru

Zmeneno:
- katalog konektoru uz neni jen staticky seznam. Akce ze skriptu se domeruji
  prekryvem v src/data/connectors.ts, takze se naraz objevi ve validaci
  stromu, ve vypoctu scope i v sablonach. Pri stejnem ID vyhrava skript
- ConnectorOperation ma implementation a scriptId
- ApiError na klientovi nese cele telo odpovedi a umi z nej vytahnout issues
- Dockerfile kopiruje scripts/ do vysledneho image

Ukladani nemuze rozbit fungujici skript: kod se nejdriv zapise do docasneho
souboru, ten se nacte a overi, a az pak prepise puvodni.

K tomu tri dokumenty navrhu dalsich kroku: 09 datove modely a prava,
10 runtime a rozpocet na 150 klientu, 11 popis skriptu konektoru.

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 13:37:58 +02:00
co-authored by Claude Opus 5
parent bbc2236c0d
commit 6f6b287d7e
34 changed files with 5546 additions and 14 deletions
+31
View File
@@ -8,9 +8,15 @@
*/
import { randomBytes } from 'node:crypto';
import path from 'node:path';
const isProduction = process.env.NODE_ENV === 'production';
function positiveNumber(value: string | undefined, fallback: number): number {
const parsed = Number(value);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
/**
* Tajny klic pro podpis tokenu.
*
@@ -68,6 +74,31 @@ export const config = {
* relativni tvar - nikdy se nehardcoduje produkcni domena.
*/
publicOrigin: (process.env.PUBLIC_ORIGIN ?? '').trim().replace(/\/+$/, ''),
// ------------------------------------------------------- skripty konektoru
/**
* Adresar se skripty konektoru. Relativne k adresari, ze ktereho aplikace
* bezi, aby to fungovalo v containeru (`/app/scripts`) i lokalne.
*/
scriptsDir: path.resolve(process.env.SCRIPTS_DIR ?? path.join(process.cwd(), 'scripts')),
/**
* Zaklad adres napojenych sluzeb, napr. "https://services.csbot.cz/apps".
* Konkretni konektor lze presmerovat pres `<KONEKTOR>_BASE_URL`.
* Nikdy se nehardcoduje do logiky, viz AGENTS.md.
*/
servicesBaseUrl: (process.env.SERVICES_BASE_URL ?? 'https://services.csbot.cz/apps')
.trim()
.replace(/\/+$/, ''),
/** Strop na jeden beh skriptu, kdyz si ho manifest neurci sam. */
scriptTimeoutMs: positiveNumber(process.env.SCRIPT_TIMEOUT_MS, 15_000),
/** Vetsi odpoved cizi sluzby se zahodi, misto aby snedla pamet procesu. */
scriptMaxResponseBytes: positiveNumber(process.env.SCRIPT_MAX_RESPONSE_BYTES, 1_000_000),
/**
* Povoli skriptum volat na localhost a do privatnich rozsahu IP.
* Jen pro lokalni vyvoj, v nasazeni musi zustat vypnute.
*/
allowPrivateTargets: process.env.ALLOW_PRIVATE_TARGETS === 'true',
};
/** Zaklad verejne adresy aplikace vcetne prefixu proxy. */