Files
lgcosta e0bef77e31
ci / check (push) Successful in 4m12s
refactor: integra reconcile no boot, dedup categoria/pasta, CI, Go 1.24
- Boot chama ReconcileBlobs com log de órfãos (era código morto)
- treeNode/validTreeName/siblingDup/moveCreatesCycle compartilhados
  entre Create/Update Category/Folder (mesma regra, um só lugar)
- mapStoreErrorFor com mensagens 404 por recurso (nota/arquivo/pasta/categoria)
- revisionHash helper + teste GET /revisions/{hash} (200 + 404)
- ReconcileBlobs com lock curto (coleta sob RLock, I/O fora do lock)
- AddFile com LimitReader no stream (cap antes de gravar, não depois)
- DeleteFile/DeleteFolder transacionais com rollback em memória
- attachmentKind único no frontend (syntax/html/preview)
- CI: gofmt, vet, test -race, node --check; go.mod 1.24 = Dockerfile
- README: notas operacionais (memória, proxy, boot, SSE, 413/400)
2026-11-05 19:57:38 -03:00

44 lines
1.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package api
import (
"net/http"
"strings"
)
const maxBody = 4 << 20 // folga sobre o limite de conteúdo da store (2 MiB)
// maxRenderInput limita o tamanho do markdown aceito pelo endpoint de render:
// conversão goldmark é O(n)–O(n²) por extensão; sem cap, 1 MiB perverso de
// entrada produz ~2 MiB de HTML (amplificação medida) e consome CPU.
const maxRenderInput = 512 << 10 // 512 KiB
type renderInput struct {
Content string `json:"content"`
Format string `json:"format"`
}
// handleRender converte Markdown em HTML seguro (raw HTML do markdown é
// escapado pelo goldmark; a nota em si é sempre renderizada via innerHTML).
func (s *Server) handleRender(w http.ResponseWriter, r *http.Request) {
var in renderInput
if err := decodeJSON(w, r, &in, maxBody); err != nil {
return
}
if len(in.Content) > maxRenderInput {
writeError(w, http.StatusRequestEntityTooLarge, "conteúdo para render excede 512 KiB")
return
}
switch in.Format {
case "html":
// O preview de HTML usa iframe com sandbox no cliente; não renderiza aqui.
writeError(w, http.StatusBadRequest, "formato html usa preview em iframe")
return
}
var buf strings.Builder
if err := s.md.Convert([]byte(in.Content), &buf); err != nil {
writeError(w, http.StatusInternalServerError, "falha ao renderizar markdown")
return
}
writeJSON(w, http.StatusOK, map[string]string{"html": buf.String()})
}