Passa al contenuto principale

Espelli la tua dashboard

Pubblicare su Vibedasher è la normale fine del ciclo: è ciò che mantiene una dashboard ospitata, governata e collegata a dati che qualcuno mantiene. L'espulsione è l'altra porta, ed è aperta di proposito. La dashboard è semplice React e SQL, e in qualsiasi momento puoi prendere l'intero albero ed eseguirlo nella tua app, sul tuo hosting, sotto la tua build.

Non è l'export di un'immagine o di un blob JSON che dovresti reimplementare. Sono i sorgenti che girano: componenti, pagine, grafici, store, hook, un package.json ricostruito dagli import reali dell'albero, una configurazione Tailwind, un entry CSS, un tsconfig.json, una configurazione Vite, un index.html, e un main.tsx che monta il tutto. npm install && npm run dev lo serve come una sua app React.

note

L'espulsione è l'opposto dell'incorporazione. Incorporare mette la nostra dashboard renderizzata dentro un iframe nella tua pagina. Espellere ti consegna i sorgenti e ci toglie completamente dal percorso di rendering — noi manteniamo solo il motore dati sottostante. Se la domanda è "questo codice è mio?", l'espulsione è la risposta. Se stai ancora scegliendo tra le due, Incorporare o espellere le mette a confronto.

Le tre chiamate​

  • eject_viz(viz_id, out_dir=...) — l'intero albero più un manifest di cablaggio: il contratto di query, i token del tema, l'entry point e l'ordine delle sue prop, l'elenco dei file, la regione e la corsia dati.
  • eject_viz_files(viz_id, paths=[...]) — il contenuto dei file su richiesta. È il seguito quando una risposta è stata paginata, ed è anche il modo economico di leggere un singolo file.
  • eject_instructions() — il riferimento di cablaggio, restituito come dati strutturati invece che come prosa da interpretare. Tutto in questa pagina è una lettura di esso; chiamalo quando vuoi l'originale leggibile dalla macchina.

Passa out_dir, e sappi su quale trasporto sei​

Una dashboard reale è nell'ordine di una quarantina di file e mezzo milione di caratteri. Con out_dir impostato su un percorso assoluto, l'albero viene scritto direttamente su disco e la risposta resta piccola per quanto grande sia l'albero.

Sul trasporto stdio — l'avvio standard, in cui il tuo client MCP lancia il server come sottoprocesso locale sotto il tuo utente — quel percorso è il tuo disco, ed è questo che rende legittimo scriverci. Sul trasporto HTTP sarebbe il disco del server, quindi lì out_dir viene rifiutato invece di scrivere file in un posto che non puoi leggere riportando successo. Sull'HTTP la paginazione è l'unica strada.

Senza out_dir, i file vengono impacchettati nella risposta fino a un budget di caratteri e il resto torna come delivery.pendingPaths. Quell'elenco è il contratto: una risposta con un pendingPaths non vuoto è una pagina, non un albero. Continua a chiamare eject_viz_files con esso finché non torna vuoto.

Leggi manifest.dataLane prima di scrivere qualsiasi cablaggio dati​

È la prima decisione e quella che non puoi cambiare dopo, perché decide chi può leggere la dashboard.

Corsia A — dataLane.id == "wasm": rende già dati reali​

Per una viz pubblica e pubblicata, l'espulsione emette un piccolo runner (vibedasherWasm.ts) e l'albero rende righe reali su npm run dev senza alcuna credenziale di alcun tipo: nessuna chiave API, nessun token di incorporazione, nessun backend tuo, e funziona da qualsiasi origine incluso localhost e un semplice server di file statici.

Il meccanismo: una GET anonima per il piano wasm della viz restituisce un estratto Parquet prefirmato per dataset; il runner registra ciascuno sotto il suo alias SQL in DuckDB-WASM ed esegue l'SQL di ogni grafico nel browser del visitatore. La sua unica dipendenza, @duckdb/duckdb-wasm, è su npm. main.tsx attende il riscaldamento del runner prima di montare, così una configurazione rotta è un pannello disegnato invece di una griglia di tile vuoti.

Qui non c'è nulla da cablare. Non aggiungerci una credenziale sopra — ti compra un bootstrap rotto in cambio di niente.

Cosa questa corsia non è: serve l'estratto pubblicato, non una query dal vivo, quindi aggiornare ciò che mostra significa ripubblicare. Ed esiste solo finché la viz resta pubblica e pubblicata.

Cosa ottiene ogni visitatore, detto chiaramente. L'estratto ha come chiave il dataset e lo snapshot, mai una query — lo stesso SELECT con e senza WHERE restituisce lo stesso file identico. Quindi contiene tutte le righe di ogni dataset che la dashboard legge, ed è un unico file, lo stesso, per tutti. Un filtro che aggiungi nella pagina cambia ciò che viene disegnato, mai ciò che è stato consegnato, e i byte sono nel tab di rete in ogni caso. È inerente al mettere i dati nel browser. Se i visualizzatori devono vedere righe diverse, prendi la corsia B.

Corsia B — dataLane.id == "token": qualsiasi altra viz​

Non c'è alcuna corsia senza credenziali e l'espulsione non ne ha emessa una. L'endpoint del piano wasm è protetto dallo stesso controllo pubblica-e-pubblicata del resto della superficie anonima, quindi puntarci a mano non aiuta. npm run dev monta comunque, e disegna un pannello che nomina l'endpoint che gli serve — non fallisce in silenzio e non sostituisce dati finti.

Due cablaggi funzionano, ed entrambi mettono la credenziale su un server che controlli tu:

  1. La tua app serve una route per il token di incorporazione. Same-origin, che risponde application/json {"token": "..."}, generato con la chiave API che tiene lato server. Punta l'URL del token di incorporazione dell'albero su di essa e costruisci il client con il token.
  2. Interroghi in codice server fidato con new Vibedasher({ apiKey }) e passi il risultato più in basso, oppure fai da proxy a { sql, params } attraverso una tua route.

Non mettere mai una chiave API nel codice del browser. Porta l'autorità completa sull'account e non ha scope. Un token di incorporazione con scope è la credenziale lato client; una chiave API no.

Questi due sono anche le sole forme che possono mostrare a un visualizzatore meno righe che a un altro. Un token di incorporazione può portare filters, che la piattaforma appende a ogni query che autorizza — lato server, prima di qualsiasi join, aggregazione o LIMIT, dove la pagina non può allargarli. In codice server fidato restringi tu stesso l'SQL.

Se l'espulsione riporta la corsia token con la ragione no-wasm-extract su una viz che è pubblica e pubblicata, il dataset semplicemente non ha ancora un estratto. Chiederlo è la sola cosa che lo costruisce — vedi La corsia di query wasm. Ripubblicare non cuoce un estratto, quindi "pubblica ed espelli di nuovo" gira all'infinito.

Installa il client​

npm i @vibedasher/client
pip install vibedasher

Il pacchetto npm è @vibedasher/client. Non esiste @vibedasher/sdk e non esisterà mai. Installa i pacchetti reali invece di copiarli dentro il tuo progetto.

Stili, typecheck e l'App Router​

Gli stili sono tre pezzi e ti servono tutti e tre. tailwind.config.js (dark mode con una strategia a selettore legata a un attributo che l'albero mette sulla propria radice, così che il dark mode della dashboard sia delimitato indipendentemente da quello della tua app, più una safelist per le classi assemblate a runtime e quindi invisibili allo scanner di Tailwind); styles/dashboard.css (l'entry di Tailwind e un blocco :root di token di design come default a tempo di build); e themeStyles.ts (gli stessi token come stringa che l'app inietta a runtime, per tema). Il CSS ti dà un primo disegno già a tema; themeStyles.ts ti dà il passaggio dal vivo tra chiaro e scuro. Se la tua app usa già Tailwind con un dark mode basato su classi, non unire le configurazioni — una configurazione Tailwind supporta una sola impostazione di dark mode. Su Tailwind v4, fai riferimento alla configurazione fornita con @config.

Typecheck. npm run typecheck (tsc --noEmit) dovrebbe riportare zero errori su un albero appena espulso, e due gate lo garantiscono a ogni esecuzione della nostra suite di test — uno fa il typecheck di un'espulsione generata completa, l'altro installa, fa il typecheck e costruisce una scritta a mano. Due condizioni delimitano l'affermazione, e nessuna delle due è una riserva. Vale sotto il tsconfig.json fornito, che imposta strict: false di proposito, perché gli effetti grafico generati sono scritti su righe di query tipizzate in modo lasco; attivare strict produrrà errori che saranno poi tuoi da mantenere. E vale per un albero i cui file di branch sono stati scritti di recente — una dashboard pubblicata abbastanza tempo fa porta file congelati di una forma più vecchia, due punti della quale è noto che falliscono tsc pur costruendo e funzionando correttamente, dato che Vite traspila senza fare il typecheck. La soluzione è ripubblicare, che riscrive i file di branch dalla forma attuale.

Next.js App Router. Ogni modulo è un server component per default. App.tsx e i moduli stores/ portano già 'use client' nell'espulsione — gli store toccano localStorage a livello di modulo e andrebbero in crash sul server. Marcare App.tsx mette tutto il suo grafo di import nel bundle client, quindi nient'altro ha bisogno della direttiva a meno che non importi un grafico, un componente o uno store direttamente da un server component.

Cosa l'espulsione non ti consegna​

  • Tutto ciò che è in manifest.internalDescriptors — metadati di piattaforma, già esclusi da files. Non copiarli.
  • Tutto ciò che è in manifest.hostOnlyImports — serviti dal bundle del nostro renderer, su nessun registro, deliberatamente assenti. Sostituiscili prima di costruire.
  • La piattaforma dati. L'espulsione ci toglie dal percorso di rendering, non dal percorso dei dati. Le connessioni, i dataset, gli aggiornamenti, i progetti dbt, la governance e il motore di query sottostanti restano dove sono mantenuti — è la metà della divisione che non stavi cercando di possedere. La corsia senza credenziali è l'unica eccezione, e solo perché legge un estratto pubblicato invece di interrogare dal vivo.