Osadź edytor TOML na swojej stronie
Dla programistów: jak umieścić edytor TOML na własnej stronie - w ramce iframe, we własnym oknie albo jako podgląd tylko do odczytu - i jak dokumenty, zapisy i wyniki AI przechodzą między edytorem a twoim serwerem. Nie potrzebujesz rejestracji ani klucza od nas.
Każda strona https (i localhost) może osadzić edytor za pomocą <iframe> i ?embed=1 - bez rejestracji, bez klucza. Po osadzeniu edytor ukrywa tekst strony i pokazuje przycisk Zapisz. Dokument można przekazywać do edytora i z niego na cztery sposoby.
1. Otwieranie pliku z linku, zapis na twoim serwerze
src= otwiera plik (twój serwer musi zezwalać na CORS), webhook= sprawia, że „Zapisz” (Ctrl+S) wysyła dokument pod ten adres. Dodaj &auto, aby zapisywać po każdej zmianie.
<iframe src="https://toml.giit.ch/pl/?embed=1&src=https://your-site.com/config/app.toml&webhook=https://your-site.com/save.php"
allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
Webhook otrzymuje żądanie POST z JSON { editor: "toml", event: "save", id, name, content, updated }. Link nie zawiera tokenu (trafiłby on do logów serwera i historii przeglądarki), więc webhook podany w adresie nadaje się do zapisu pod adresem, który nie wymaga tokenu, na przykład na localhost lub w intranecie. W przypadku publicznego serwera przekaż webhook z tokenem w tomleditor:load (hook: { url, token }) i zweryfikuj go, tak jak robi to ten krótki skrypt PHP:
<?php
header('Access-Control-Allow-Origin: https://toml.giit.ch');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Methods: POST, OPTIONS');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit;
if (($_SERVER['HTTP_AUTHORIZATION'] ?? '') !== 'Bearer SECRET') { http_response_code(403); exit; }
$d = json_decode(file_get_contents('php://input'), true);
$name = preg_replace('/[^\w\- ]/u', '_', $d['name']);
file_put_contents(__DIR__ . "/config/$name.toml", $d['content']);
echo '{"ok":true}';
2. Dokument przechowuje twoja strona (postMessage)
Edytor zgłasza tomleditor:ready, twoja strona odpowiada tomleditor:load, edytor zgłasza tomleditor:loaded, tomleditor:change przy rzeczywistych zmianach i tomleditor:save, gdy użytkownik zapisuje. Twoja strona może wysłać tomleditor:get (bieżący stan) lub tomleditor:save (naciśnięcie Zapisz). Zapis odbywa się wtedy przez twoje własne logowanie i sesję.
<iframe id="ed" src="https://toml.giit.ch/pl/?embed=1" allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
<script>
const ed = document.getElementById('ed');
const ORIGIN = 'https://toml.giit.ch';
addEventListener('message', async e => {
if (e.source !== ed.contentWindow || e.origin !== ORIGIN) return;
const m = e.data;
if (m.type === 'tomleditor:ready') { // edytor jest gotowy: przekaż mu dokument
ed.contentWindow.postMessage({
type: 'tomleditor:load',
name: 'Settings',
content: await (await fetch('/config/app.toml')).text()
}, ORIGIN);
}
if (m.type === 'tomleditor:change') document.title = '● not saved'; // rzeczywista zmiana
if (m.type === 'tomleditor:save') { // użytkownik kliknął „Zapisz”
await fetch('/api/save', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: m.name, content: m.content }) });
document.title = 'Saved';
}
});
// Przycisk zapisu na twojej stronie: odpowiedź przychodzi jako tomleditor:save
function saveNow() { ed.contentWindow.postMessage({ type: 'tomleditor:get' }, ORIGIN); }
</script>
Asystent AI na twojej stronie: działa także w ramce. Z allow="clipboard-write" w iframe „Kopiuj prompt” korzysta bezpośrednio ze schowka (w przeciwnym razie edytor używa starego polecenia kopiowania albo pokazuje prompt do ręcznego skopiowania). Link wysłany przez AI nie dotrze do edytora osadzonego w innej stronie, więc edytor prosi AI i użytkownika o wklejenie całej odpowiedzi AI do edytora - albo o otwarcie edytora we własnym oknie.
3. We własnym oknie
window.open("https://toml.giit.ch/pl/?embed=window", "tomleditor-17") otwiera pełny edytor we własnym oknie, który wymienia te same wiadomości z window.opener. Linki od AI docierają do niego tam. tomleditor:load może też zawierać context: { host, title, rules } - prompt dla AI mówi wtedy, gdzie należy dokument, i stosuje twoje zasady - oraz hook: { url, token }, webhook tylko dla tego dokumentu, który nigdy nie jest zapisywany. Zamknięcie okna z niezapisanymi zmianami wysyła tomleditor:closing.
4. AI przez twój własny serwer
Przekaż edytorowi własny prompt, adres w twojej witrynie i klucz dla tej sesji edytora. Okno AI pokazuje wtedy „Połączono z” twoją witryną, to, co przekazujesz AI, oraz wybór: zmienić bieżący dokument lub utworzyć nowy; Kopiuj prompt łączy to wszystko. AI wysyła swój wynik z kluczem na twój serwer, a twoja strona otwiera go w edytorze - nowy dokument otwiera się osobno i zostaje w przeglądarce użytkownika. Jeden klucz na sesję edytora: pozostaje ważny, dopóki edytor jest otwarty, a edytor prosi o niego przez tomleditor:key-request tylko wtedy, gdy go nie ma. Edytor nigdy sam nie wysyła klucza i nigdy go nie zapisuje; adres musi być adresem https na twoim własnym hoście lub jego subdomenie.
const key = async () => (await fetch('/api/ai-key.php?doc=17')).json(); // jeden klucz na sesję edytora
const k = await key();
ed.contentWindow.postMessage({ type: 'tomleditor:load', name: 'Settings', content, ai: {
label: 'My Site', prompt: 'Keep every key and every comment.',
endpoint: 'https://your-site.com/api/ai-result.php', key: k.key } }, ORIGIN);
// zapamiętaj id z tomleditor:loaded i ignoruj change/save/closing z innym id
// tylko gdy edytor nie ma klucza:
if (m.type === 'tomleditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'tomleditor:ai', key: k.key }, ORIGIN); }
// dopóki edytor jest otwarty, informuj serwer co minutę; zamknięcie edytora lub strony unieważnia klucz
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// twój serwer ma wynik (polling, SSE …): target to "current" lub "new"
ed.contentWindow.postMessage({ type: 'tomleditor:load', name: 'Settings', content: draft, from: 'ai', target }, ORIGIN);
Twórz klucze z co najmniej 128 losowymi bitami, przechowuj tylko ich hash, wiąż każdy z zalogowanym użytkownikiem, dokumentem i tą sesją edytora, twórz jeden na sesję, utrzymuj go ważnym tylko wtedy, gdy twoja strona zgłasza sesję jako otwartą, i unieważniaj go, gdy edytor lub strona zostaną zamknięte.
Cały protokół jest opisany w llms.txt - przekaż go AI, a zbuduje połączenie dla twojego systemu. Pozostałe edytory giit działają tak samo, każdy z własnym prefiksem - editors.giit.ch.
Wyświetlanie dokumentu tylko do odczytu (przeglądarka)
?viewer=1 pokazuje tylko gotowy dokument: bez kodu, bez narzędzi, niczego nie można zmienić i nic nie jest zapisywane w przeglądarce. Dokument pochodzi z linku (#b64=, ?src=), z Twojej strony przez tomleditor:load albo przez POST jako zwykły formularz do post.php: pole content jako tekst lub b64 jako base64, opcjonalnie name, najwyżej 20 MB tekstu.
<form method="post" action="https://toml.giit.ch/post.php?viewer=1" target="_blank">
<input type="hidden" name="lang" value="pl">
<input type="hidden" name="name" value="Report">
<input type="hidden" name="b64" value="…">
<button>Open</button>
</form>
Bez viewer=1 dokument otwiera się w zwykłym edytorze. W obu przypadkach pozostaje tylko w pamięci: nie jest zapisywany na serwerze i nie trafia do "Moich dokumentów". Otwarta bezpośrednio przeglądarka informuje, że treść pochodzi od osób trzecich.