curl and Terminal Clients

curl, Wget, HTTPie and xh get a page's first frame as truecolor ANSI text. Configure its size or turn it off.

I client HTTP da terminale ricevono il primo frame di una pagina come testo ANSI truecolor invece del documento HTML. Non devi configurare nulla.

curl https://my-app.example.com/about

Richieste che ricevono un frame

Una richiesta riceve un frame quando tutte queste condizioni sono soddisfatte:

  • il metodo è GET o HEAD;
  • lo User-Agent inizia con curl/, Wget/, wget2/, HTTPie/ o xh/;
  • l’header Accept è assente o non menziona text/html.

Browser, crawler e anteprime dei link ricevono la pagina HTML. Per ottenere l’HTML da curl, richiedilo:

curl -H 'Accept: text/html' https://my-app.example.com/about

Il frame viene scelto nel punto in cui la pagina sarebbe servita: dopo middleware, rewrites e route handler, e mai per file o percorsi il cui ultimo segmento contiene un punto. Reindirizzamenti del middleware, 401, header e riscritture si applicano a curl come ai browser. /api/health esegue comunque il proprio handler e /robots.txt serve comunque il file.

Contenuto del frame

Il frame è il primo rendering della pagina, come in una shell con pre-rendering: ogni boundary <Suspense> ancora in attesa mostra il proprio fallback. I componenti server asincroni non vengono eseguiti e fetch() non si risolve mai, quindi i dati caricati negli effetti restano nello stato di caricamento.

  • Dimensioni: 80 × 24 celle. Un’app con viewport fisso (viewport.responsive: false) usa invece viewport.width × viewport.height.
  • Colori: codici di escape SGR a 24 bit nel viewport.theme dell’app. Ogni riga termina con un reset e il frame termina con un carattere di nuova riga.
  • Stato: 200, oppure 404 con la pagina non trovata dell’app quando nessuna pagina corrisponde o la pagina chiama notFound(). Una pagina che chiama redirect() durante il rendering serve HTML.

Le risposte sono text/plain; charset=utf-8 con Vary: User-Agent, Accept e Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate, quindi le cache condivise non memorizzano mai un frame per poi servirlo a un browser. La pagina HTML a un percorso in cui curl riceve un frame include lo stesso header Vary.

Ambienti supportati

HostPagine statichePagine dinamiche, percorsi sconosciuti
text devRendering su richiestaRendering su richiesta
text start, bunPre-rendering con text buildRendering su richiesta
vercel, cloudflarePre-rendering con text buildPagina HTML
staticPagina HTMLPagina HTML

Le pagine renderizzate lato server richiedono text start o bun (vedi Deploy).

Gli host statici non possono rispondere a un client in modo diverso da un altro, quindi l’adapter static non supporta i frame. Su Vercel e Cloudflare, i frame delle pagine statiche sono inclusi nella build. Lì le pagine dinamiche ([id], force-dynamic) servono HTML, perché gli adapter vercel e cloudflare non eseguono il deploy di un renderer.

text start e bun dist/server.js eseguono il rendering delle pagine rimanenti su richiesta con .text/server/live.mjs e conservano gli ultimi 128 frame per 10 secondi. Ogni server esegue il rendering di un massimo di 20 pagine non in cache ogni 10 secondi. Oltre questo limite, curl riceve la pagina HTML finché il budget non si ripristina. Se non è possibile caricare live.mjs sul server, per esempio perché un modulo di pagina legge window al livello principale, quelle pagine servono HTML.

text build riporta i frame generati dal pre-rendering:

 ✓ Prerendering curl frames (5/5)

Configurazione

Modifica le dimensioni per l’intera app o disattiva i frame:

text.config.tsts
import { defineConfig } from "@textjs/app";export default defineConfig({  ansi: { cols: 100, rows: 30 },  // ansi: false,});

Una pagina può modificare le proprie dimensioni o servire HTML anche ai terminali:

app/dashboard/page.tsxtsx
export const ansi = { cols: 120, rows: 40 };// export const ansi = false;

Le dimensioni sono limitate a 1–500 celle. Con ansi: false in text.config.ts, le esportazioni delle pagine vengono ignorate.

HTTP non cifrato

curl non segue i reindirizzamenti a meno che tu non passi -L. Vercel reindirizza le richieste http:// a https://, e lo stesso fa Cloudflare con Always Use HTTPS attivo, quindi curl http://… stampa il reindirizzamento invece del frame. Condividi URL https://.

Server personalizzati

@textjs/app/ansi esporta le funzioni di supporto per il rilevamento e la risposta, per server e funzioni che non eseguono text start o un adapter:

import { ansiResponse, wantsAnsi } from "@textjs/app/ansi";import { frameToAnsi } from "@textjs/react";if (wantsAnsi(request)) return ansiResponse(frameToAnsi(buffer, { theme: "geistDark" }), request.method);

wantsAnsi(request) accetta anche (method, headers) con Headers Web o IncomingHttpHeaders di Node. frameToAnsi(buffer, { theme }) codifica un CellBuffer renderizzato nello stesso modo del framework.

Modifica questa pagina su GitHub