Editor TOML
Abrir o editor

Incorpore o editor TOML ao seu site

Para desenvolvedores: como colocar o editor TOML na sua própria página - em um iframe, em uma janela própria ou como visualizador somente leitura - e como documentos, salvamentos e resultados de uma IA passam entre o editor e o seu servidor. Não é preciso cadastro nem chave nossa.

Qualquer página https (e localhost) pode incorporar o editor com um <iframe> e ?embed=1 - sem cadastro, sem chave. Incorporado, o editor oculta o texto da página e mostra um botão Salvar. Há quatro jeitos de levar o documento para dentro e para fora.

1. Abrir um arquivo de um link, salvar no seu servidor

src= abre um arquivo (seu servidor precisa permitir CORS), webhook= faz "Salvar" (Ctrl+S) enviar o documento para esse endereço. Acrescente &auto para salvar após cada alteração.

<iframe src="https://toml.giit.ch/pt/?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>

O webhook recebe um POST com JSON { editor: "toml", event: "save", id, name, content, updated }. Um link não leva token (ele acabaria nos logs do servidor e no histórico do navegador), por isso um webhook no endereço serve para um destino de salvamento que não exija token, por exemplo em localhost ou na sua intranet. Para um servidor público, passe o webhook com um token em tomleditor:load (hook: { url, token }) e valide o token, como faz este pequeno script 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. A sua página guarda o documento (postMessage)

O editor diz tomleditor:ready, a sua página responde com tomleditor:load, o editor informa tomleditor:loaded, tomleditor:change em edições reais e tomleditor:save quando o usuário salva. A sua página pode enviar tomleditor:get (o estado atual) ou tomleditor:save (apertar Salvar). Salvar passa então pelo seu próprio login e sessão.

<iframe id="ed" src="https://toml.giit.ch/pt/?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') {              // o editor está pronto: entregue o documento a ele
    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';   // uma edição real
  if (m.type === 'tomleditor:save') {               // o usuário clicou em "Salvar"
    await fetch('/api/save', { method: 'POST', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: m.name, content: m.content }) });
    document.title = 'Saved';
  }
});

// Um botão de salvar na sua própria página: a resposta chega como tomleditor:save
function saveNow() { ed.contentWindow.postMessage({ type: 'tomleditor:get' }, ORIGIN); }
</script>

Assistente de IA dentro da sua página: ele também funciona no frame. Com allow="clipboard-write" no iframe, "Copiar prompt" usa a área de transferência diretamente (senão o editor recorre ao antigo comando de copiar, ou mostra o prompt para copiar à mão). Um link enviado pela IA não alcança um editor dentro de outro site, então o editor pede à IA e ao usuário que colem a resposta inteira da IA no editor - ou abram o editor em uma janela própria.

3. Em uma janela própria

window.open("https://toml.giit.ch/pt/?embed=window", "tomleditor-17") abre o editor completo em uma janela própria e troca as mesmas mensagens com window.opener. Os links de uma IA chegam até ele ali. tomleditor:load também pode levar context: { host, title, rules } - o prompt da IA então diz a que lugar o documento pertence e segue as suas regras - e hook: { url, token }, um webhook só para este documento que nunca é guardado. Fechar a janela com alterações não salvas envia tomleditor:closing.

4. IA pelo seu próprio servidor

Entregue ao editor o seu próprio prompt, um endereço no seu site e uma chave para esta sessão do editor. A janela de IA mostra então "Conectado a" o seu site, o que você diz à IA, e a escolha alterar o documento atual ou criar um novo; Copiar prompt junta tudo. A IA envia o resultado com a chave para o seu servidor, e a sua página o abre no editor - um novo documento abre separado e fica no navegador do usuário. Uma chave por sessão do editor: ela vale enquanto o editor estiver aberto, e só enquanto não tiver nenhuma o editor a pede com tomleditor:key-request. O editor nunca envia a chave por conta própria e nunca a guarda; o endereço precisa ser https no seu próprio host ou em um subdomínio dele.

const key = async () => (await fetch('/api/ai-key.php?doc=17')).json();   // uma chave por sessão do editor
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);
// guarde o id de tomleditor:loaded e ignore change/save/closing com outro id
// só enquanto o editor não tiver chave:
if (m.type === 'tomleditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'tomleditor:ai', key: k.key }, ORIGIN); }
// enquanto o editor estiver aberto, avise o seu servidor a cada minuto; fechar o editor ou a página invalida a chave
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// o seu servidor tem um resultado (polling, SSE …): target é "current" ou "new"
ed.contentWindow.postMessage({ type: 'tomleditor:load', name: 'Settings', content: draft, from: 'ai', target }, ORIGIN);

Crie chaves com pelo menos 128 bits aleatórios, guarde só o hash delas, vincule cada uma ao usuário logado, ao documento e a esta sessão do editor, crie uma por sessão, mantenha-a válida só enquanto a sua página informar que a sessão está aberta, e invalide-a quando o editor ou a página fechar.

O protocolo completo está em llms.txt - entregue-o a uma IA e ela monta a conexão para o seu sistema. Os outros editores giit funcionam do mesmo jeito, cada um com o próprio prefixo - editors.giit.ch.

Mostrar um documento somente para leitura (visualizador)

?viewer=1 mostra apenas o documento pronto: sem código, sem ferramentas, nada pode ser alterado e nada é salvo no navegador. O documento vem de um link (#b64=, ?src=), da sua página com tomleditor:load ou por POST como formulário normal para post.php: o campo content como texto ou b64 como base64, opcionalmente name, no máximo 20 MB de texto.

<form method="post" action="https://toml.giit.ch/post.php?viewer=1" target="_blank">
  <input type="hidden" name="lang" value="pt">
  <input type="hidden" name="name" value="Report">
  <input type="hidden" name="b64" value="…">
  <button>Open</button>
</form>

Sem viewer=1 o documento abre no editor normal. Em ambos os casos ele fica apenas na memória: não é salvo no servidor nem entra em "Meus documentos". Aberto diretamente, o visualizador informa que o conteúdo vem de terceiros.