Pular para o conteúdo principal

Clepit

Num relance

Categoria
Plataforma para programadores
Site
clepit.com
Consola
app.clepit.com
Documentação
clepit.com/en/docs
API GraphQL
api.clepit.com/graphql
Tempo real
ws.clepit.com
Superfície MCP
api.clepit.com/mcp
Páginas publicadas
clepit.space

A maior parte do texto formatado acaba na base de dados como um bloco de HTML. Isso serve enquanto não quiser fazer com ele nada além de o mostrar de novo: encontrar todas as páginas que mencionam um cliente, apresentar o mesmo documento numa página web, num e-mail e numa aplicação móvel, ou deixar duas pessoas editá-lo ao mesmo tempo sem que uma delas perca um parágrafo. A essa altura as palavras e a sua formatação estão enredadas, e a única coisa capaz de ler o documento com segurança é o editor que o escreveu.

O Clepit mantém as duas coisas separadas. Uma página é uma lista de blocos, cada um um pequeno objeto tipado, e o documento é JSON: nenhuma marcação para analisar e nenhum editor necessário para o ler. É também por isso que o editor se aguenta sozinho. O @clepit/core está publicado no npm sob licença MIT e nada sabe do lado alojado, enquanto o espaço de trabalho em app.clepit.com é aquilo em que esses mesmos documentos se tornam quando recebem colaboradores, permissões, histórico e um endereço na web pública.

Uma página é uma lista de blocos

Um bloco são quatro campos: um id, um tipo, os dados que esse tipo define e os ajustes que lhe foram aplicados. Os dados de um parágrafo têm uma forma diferente dos de uma tabela, e é o tipo que diz qual forma esperar, de modo que um documento guardado pode ser verificado e não apenas analisado. Uma página inteira é uma marca temporal, uma versão e os blocos por ordem, pequena o bastante para ser lida a olho nu e revista num pull request. Nada nela descreve o aspeto que a página deve ter: isso pertence a quem a desenha, e é o que permite que um documento se torne página web, e-mail e ecrã de telemóvel sem que existam três cópias dele.

Desenhar um documento sem navegador

O renderizador nunca escreve diretamente no navegador. Desenha através de uma camada fina com dois suportes por trás: um constrói nós reais de página e o outro constrói uma cadeia de texto, e o mesmo código de bloco corre em ambos. É assim que uma página publicada é desenhada num servidor onde não existe navegador algum, e é por isso que aquilo que o servidor produz é o mesmo documento que o editor teria mostrado, e não uma segunda implementação deixada a divergir. O suporte de texto exige um sanitizador como argumento obrigatório e de propósito não tem valor por omissão: o sanitizador habitual do pacote constrói uma página para poder analisar, logo não pode correr ali, e recuar em silêncio para o escape despiria a formatação interna de todos os documentos sem o dizer. A falha fica portanto visível no sítio onde é usada, em vez de escondida num valor por omissão.

Ler não custa ao leitor nenhum JavaScript

O adaptador React entrega as suas duas metades em separado, porque querem coisas opostas. O componente de conteúdo corre no servidor e emite marcação acabada enquanto a página está a ser construída, pelo que o leitor recebe o documento logo na primeira resposta. O componente de edição vive apenas do lado do cliente, já que toma conta do ciclo de vida do editor, e nada há para tomar conta enquanto não existir um navegador. Ler um documento Clepit não precisa, portanto, de JavaScript nenhum. É a escrever que o tempo de execução chega.

O que uma página pode conter

Vinte e seis tipos de bloco vêm no pacote. A maioria são os de que qualquer editor precisa: títulos, parágrafos, listas, listas de verificação, citações, código, tabelas, imagens, áudio, vídeo, ficheiros, caixas de aviso e separadores. Os restantes existem porque escrever documentação pede coisas que uma ferramenta de escrita costuma ignorar. Um índice que se constrói sozinho a partir dos títulos do documento e liga a cada um deles. Secções que se dobram e colunas. Um cartão que faz as vezes de outra página. Um esboço à mão livre. E um bloco de atividade que guarda qual documento vigiar, e não uma cópia da atividade dele, pelo que continua a mostrar o que está a acontecer agora em vez de congelar no dia em que foi inserido. A formatação dentro de um bloco cobre as marcas habituais, negrito, itálico, sublinhado, riscado, código na linha, realce e ligações, além de balões de ajuda, etiquetas de estado e menções. O pacote em si não tem dependências de execução de espécie alguma.

Fórmulas e diagramas, desenhados dentro do pacote

Dois desses blocos apresentam LaTeX e Mermaid, e ambos fazem o trabalho todo dentro do pacote: analisam a fonte, calculam a disposição, desenham o resultado. Não há biblioteca de desenho por baixo nem chamada a serviço algum para transformar uma fórmula ou um fluxograma numa imagem. Isso é menos uma preferência quanto a dependências do que uma consequência do suporte de texto. Um bloco que fosse buscar algo que só um navegador fornece, ou que fosse buscar a rede, não poderia ser desenhado no servidor que serve as páginas publicadas, e a mesma página passaria então a ter aspeto diferente consoante quem a pedisse.

Uma referência de API que vive na página

Dê ao bloco OpenAPI uma especificação, colada ou indicada por endereço, e ele desenha aquilo que a especificação descreve: as operações, os seus caminhos e parâmetros, os esquemas de pedido e resposta, e o modo de autenticação. Para cada operação constrói ainda um excerto de pedido em cURL, TypeScript, Dart e Python, gerado a partir da especificação em vez de escrito à mão por um autor que se esquecerá de o atualizar. O bloco de incorporação olha para o mundo lá fora do mesmo modo: reconhece um punhado de serviços que consegue mesmo mostrar, trata para tudo o resto uma simples ligação como um resultado legítimo e não como uma falha, e recusa-se de todo a desenhar um endereço em que não confia.

Duas pessoas no mesmo parágrafo

Uma página que está a ser editada ao vivo é mantida por uma única tarefa no servidor, uma por página, e todas as alterações passam por ela pela ordem em que chegam. É isso que torna a edição em simultâneo possível de raciocinar: não existe um segundo escritor a correr contra o primeiro. O documento em si é um CRDT, pelo que duas pessoas a escrever no mesmo parágrafo se fundem em vez de se apagarem, e um cliente que ficou para trás recupera trocando aquilo que falta a cada lado. Cada alteração é acrescentada a um registo de escrita antecipada antes de ser difundida a quem quer que seja, pelo que o que as outras pessoas no documento veem já ficou guardado de forma duradoura e não apenas retransmitido. A permissão é imposta no servidor e não na interface: quem entra sem direito de edição é despromovido a leitura, e a sessão volta a verificar esse direito periodicamente enquanto o documento está aberto, de modo que um acesso retirado atinge alguém que está mesmo a escrever em vez de esperar que recarregue a página.

Toda a escrita passa por uma só porta

Um documento pode ser alterado por alguém que escreve nele e por um programa que chama a API, e esses dois caminhos podiam antes escrever na mesma página de forma independente. Já não podem. Uma escrita vinda da API é encaminhada para a mesma sessão que detém o documento vivo, onde é aplicada como uma única transação ao lado das edições em curso, pelo que existe uma só ordem de acontecimentos em vez de dois escritores com opiniões separadas sobre o que a página diz. Os identificadores dos blocos são preservados quando o documento é escrito de volta, porque os comentários estão ancorados neles e uma reconciliação que criasse identificadores novos deixaria cada comentário a apontar para o nada. E quando o conjunto de blocos resultante é idêntico ao que já está guardado, nada é escrito.

O único transporte que uma chave de máquina não alcança

Uma chave de API pessoal funciona com REST, GraphQL, o socket de subscrições do GraphQL e MCP. Não funciona com o socket de colaboração, e isso é propositado. Cada alteração feita em colaboração é carimbada com a pessoa que a fez, e esses carimbos tornam-se a autoria registada no histórico da página. Um principal de máquina a editar ali escreveria um autor que pessoa nenhuma escreveu, e desfazer isso mais tarde significa reescrever o histórico e não apagar uma linha. A fronteira não passa entre websockets e HTTP: passa por saber se o transporte escreve histórico com autor. A regra é imposta pela forma do código e não pela memória, já que aceitar uma chave exige mudar deliberadamente para outra chamada de autenticação, e um teste falha quando um transporte o faz.

Um espaço de trabalho no seu próprio endereço

Cada espaço de trabalho é um inquilino com o seu próprio subdomínio desde o momento em que é criado, e o inquilino é determinado a partir do endereço por onde o pedido chegou. Em que inquilino está fica portanto decidido antes de qualquer dado seu ser lido, e não por um filtro aplicado depois que alguém possa esquecer. Por baixo disso, é a própria base de dados que impõe a fronteira, através de segurança ao nível da linha: cada pedido requisita uma ligação, carimba nela a identidade de quem chama, e o conjunto de ligações limpa esse estado quando a ligação é devolvida, de modo que a identidade de um pedido não pode escorrer para as consultas do pedido seguinte.

Reclamar um domínio não é o mesmo que prová-lo

Um espaço de trabalho num plano Enterprise pode servir as suas páginas a partir de um domínio próprio. Reclamar um domínio e servir a partir dele são passos propositadamente separados: o domínio é guardado por verificar, e o resolvedor ignora-o por completo até aparecer um registo de verificação no DNS. Qualquer pessoa pode escrever o endereço de outra empresa num formulário. Só quem controla esse domínio pode publicar o registo que o põe a funcionar.

Todas as versões que a página teve

O Clepit guarda revisões e não um único estado atual. É tirado um instantâneo automaticamente enquanto as pessoas trabalham, travado para que a escrita normal não produza centenas deles: é escrito um novo assim que passem dez minutos ou mudem dez blocos, o que ocorrer primeiro. Restaurar é uma única transação: aplica-se o instantâneo antigo, reconciliam-se os blocos, e a própria restauração é escrita como uma revisão nova, pelo que recuar fica registado e não desfeito em silêncio. A reconciliação preserva de propósito os identificadores dos blocos de origem, porque os comentários estão ancorados a blocos, e restaurar uma página com identificadores novos deixaria cada comentário nela sem âncora.

Voltar a encontrá-lo

A pesquisa corre sobre uma projeção das páginas, e a consulta passa pelo analisador de pesquisa web do próprio Postgres em vez de ser montada em SQL à mão, pelo que alguém pode escrever aspas e sinais de menos sem que nada disso constitua uma superfície de injeção. O que importa num espaço partilhado, porém, é onde está a verificação de permissões. A pesquisa junta a tabela das páginas, e a segurança ao nível da linha dessa tabela aplica-se à junção, pelo que os resultados já estão limitados às páginas que a pessoa que pergunta pode ver. Os filtros (um ramo da árvore de páginas, quem reviu por último, quando foi editada pela última vez) acrescentam-se a isso como condições adicionais. Cada um deles estreita; nenhum consegue alargar, porque todos estão atrás da mesma verificação.

Publicar congela, partilhar não

São duas coisas diferentes e o Clepit trata-as de forma diferente de propósito. Publicar uma página congela o documento atual como revisão, aponta a página para ela e torna-a pública: o que um visitante lê em clepit.space, num endereço como acme.clepit.space/handbook, é essa revisão congelada e não as edições feitas depois. Retirar a publicação limpa esses apontadores mas mantém o endereço público, pelo que voltar a publicar mais tarde regressa ao mesmo URL em vez de partir todas as ligações que apontavam para ali. Uma ligação de partilha é o contrário: serve o documento vivo, pelo que aquilo que o destinatário vê muda à medida que a página muda.

Uma ligação que pode retirar

Uma ligação de partilha é um sinal que pode revogar, e pode receber um prazo de validade quando é criada. Apenas se guarda um resumo criptográfico do sinal, pelo que a ligação é mostrada uma única vez na criação e depois não pode ser recuperada da base de dados, nem por nós nem por quem lá chegue. Estas ligações concedem leitura, não comentário: um comentário precisa de um autor, e quem detém uma ligação não é um.

Iniciar sessão a partir do seu próprio diretório

Um espaço de trabalho pode entregar a autenticação ao seu próprio fornecedor de identidade: OpenID Connect no plano Business, SAML no Enterprise, com SCIM ao lado para sincronizar o diretório. O SCIM cobre o recurso de utilizador que o Okta e o Entra de facto conduzem, e afasta-se de propósito da leitura óbvia da norma num ponto: um apagamento desativa o membro em vez de o eliminar. A especificação permite-o, e a alternativa é uma sincronização de diretório capaz de destruir o conteúdo de um espaço de trabalho por se ter retirado alguém de um grupo.

Quatro maneiras de falar com ele

O REST cobre quarenta e quatro operações sob /v1, descritas por um documento OpenAPI gerado a partir das próprias rotas e não escrito ao lado delas, e a integração contínua compara essa saída com a cópia versionada, pelo que uma alteração de rota que salte o registo não consegue entrar em silêncio. O GraphQL cobre o modelo da aplicação e leva as subscrições no seu próprio socket. O tempo real é um processo à parte, e é por isso que reiniciar a gateway não arrasta consigo a superfície de pedidos, e autoriza por socket em vez de por sala: a cada acontecimento, todas as ligações dentro do inquilino são avaliadas numa única verificação agrupada e só as que podem vê-lo o recebem. O MCP expõe essas mesmas operações a agentes de IA como ferramentas, e nenhuma ferramenta confia num identificador vindo de quem chama para decidir em que espaço de trabalho está a agir; as escritas passam pelos mesmos serviços que a interface usa, pelo que as verificações de permissões e o registo de auditoria são os mesmos.

Para quem é

Equipas que precisam de um editor que controlam, e programadores que integram conteúdo estruturado no seu próprio produto.

Visitar Clepit: clepit.com