Un pacchetto del sito è una copia portabile del modello dei contenuti, dei contenuti, della cronologia editoriale, della presentazione, delle impostazioni e dei file multimediali di un sito EmDash. Importa un pacchetto del sito per spostare un sito in un’altra distribuzione di EmDash, anche una che usa un database diverso: SQLite, PostgreSQL o Cloudflare D1.
Un’importazione scrive in un nuovo sito la cui area dei contenuti è vuota. EmDash controlla l’intero pacchetto prima di scrivere qualsiasi cosa, esegue l’importazione in piccoli passaggi riprendibili, rilegge il sito importato ed emette una ricevuta quando il risultato corrisponde al pacchetto.
Un pacchetto del sito non contiene utenti, credenziali né segreti. Contiene però ogni voce e ogni commento del sito, inclusi gli indirizzi email di autori e commentatori. Conservalo e invialo con la stessa cura di un backup del database.
Scegliere il tipo di copia giusto
| Meccanismo | Scopo | Importabile | File multimediali | Utenti e segreti |
|---|---|---|---|---|
| File seed | Inizializzare un modello dei contenuti e contenuti di esempio | Sì, con la semantica dei seed | No | No |
| Snapshot di anteprima | Popolare il rendering isolato delle anteprime | Solo anteprima | No | No |
| Backup JSON | Ispezionare lo stato selezionato in forma di database | No | No | No |
| Backup grezzo di database e media | Ripristinare una distribuzione | Ripristino nello stesso tipo di database | Copia separata | Sì |
| Pacchetto del sito | Spostare un sito in un altro sito EmDash | Sì, in un sito vuoto | Sì | No. Solo nomi e indirizzi email degli autori |
Usa un backup grezzo del database per ripristinare una distribuzione dopo una perdita di dati. Usa un pacchetto del sito per creare una nuova copia di un sito altrove.
Cosa contiene un pacchetto del sito
Un pacchetto del sito contiene:
- collezioni, campi, tipi di blocco con ogni versione, definizioni di tassonomie, definizioni di relazioni e definizioni dei campi byline;
- ogni voce di contenuto in ogni lingua, incluse bozze, voci programmate, voci nel cestino, cronologia delle revisioni e gruppi di traduzione;
- termini di tassonomia e assegnazioni di termini, byline e crediti, riferimenti ai contenuti e record SEO;
- menu e voci di menu, aree widget e widget, sezioni e reindirizzamenti;
- commenti e reazioni ai commenti, a meno che l’esportazione non escluda i commenti;
- cartelle multimediali, metadati dei media e i byte di ogni file multimediale pronto; e
- le impostazioni portabili del sito elencate di seguito.
Il pacchetto memorizza i valori JSON, come i campi JSON e il Portable Text, con le chiavi degli oggetti ordinate. Un valore importato può quindi elencare le proprie chiavi in un ordine diverso rispetto all’origine. Per il resto, i valori restano invariati.
Impostazioni portabili
Vengono esportate solo queste impostazioni: site:title, site:tagline, site:logo, site:favicon, site:postsPerPage, site:dateFormat, site:timezone, site:social, site:seo, emdash:site_title, emdash:site_tagline ed emdash:locale.
Il sito di destinazione mantiene il proprio URL del sito (site:url ed emdash:site_url), l’ID del sito, lo stato di configurazione e le impostazioni di backup. Un’importazione non li sovrascrive mai.
Il piano di importazione chiede se mantenere il titolo e lo slogan della destinazione, scritti dalla procedura guidata di configurazione, oppure usare i valori del pacchetto. Per impostazione predefinita vengono usati i valori del pacchetto.
Principal
Un account utente non viene mai spostato con un pacchetto. Per ogni utente di origine a cui fanno riferimento contenuti, revisioni, media, byline o commenti, il pacchetto include un principal: l’ID dell’utente, il nome visualizzato e l’indirizzo email. Un principal non ha ruolo, password, passkey, sessione né token.
Durante l’importazione, associ ogni principal a un utente del sito di destinazione oppure lo lasci senza associazione. Consulta associare gli autori agli utenti di destinazione.
Commenti
I commenti includono nome e indirizzo email dell’autore, corpo, stato, struttura delle discussioni, timestamp e metadati di moderazione. L’hash dell’indirizzo IP e lo user agent non vengono esportati.
Le reazioni mantengono il proprio conteggio. L’esportatore sostituisce ogni hash del votante con un nuovo valore casuale, così la destinazione non può associare una reazione al visitatore che l’ha espressa.
Cosa esclude un pacchetto del sito
Un pacchetto del sito non contiene mai:
- utenti, sessioni, passkey, account OAuth, domini consentiti, token API, client OAuth, codici di autorizzazione o codici dispositivo;
- archiviazione, stato o impostazioni dei plugin, inclusi i segreti dei plugin;
- impostazioni diverse da quelle portabili, come il segreto di firma delle anteprime;
- log di audit, limiti di frequenza, blocchi di modifica, stato delle attività pianificate, il log degli errori 404 o la cronologia delle migrazioni;
- record di utilizzo dei media e indici di ricerca, che l’importazione ricostruisce;
- chiavi di archiviazione, nomi dei bucket, nomi dei database o nomi dei binding dell’origine; oppure
- media non pronti, come un caricamento incompleto.
I media di un provider multimediale esterno restano esterni. Il pacchetto mantiene il riferimento, ma i file del provider non vengono copiati.
Preparare il sito di destinazione
Importa in un sito che soddisfi tutti i requisiti seguenti. Quando contenuti, lingue, limite di caricamento o formato supportato della destinazione non sono compatibili con il pacchetto, l’analisi segnala un blocco.
- Un account amministratore. L’importazione viene eseguita da un amministratore che ha effettuato l’accesso o con un token API. Crea l’amministratore della destinazione durante la configurazione.
- Un backend di archiviazione. Sia l’origine sia la destinazione hanno bisogno di un’archiviazione configurata. EmDash vi deposita temporaneamente i file del pacchetto.
- Nessun contenuto. La destinazione non deve contenere voci (incluse quelle nel cestino), revisioni, media o cartelle multimediali, byline o campi byline, commenti, reindirizzamenti, assegnazioni di termini, relazioni, record SEO, sezioni create nell’amministrazione, né collezioni o tipi di blocco creati dopo la configurazione. Un sito configurato da un qualsiasi template ufficiale soddisfa il requisito. Ciò che la configurazione ha creato è l’impalcatura di configurazione: le collezioni e i tipi di blocco creati dal seed, le definizioni di tassonomie e i relativi termini non assegnati, i menu e le loro voci, le aree widget e i loro widget, e le sezioni del tema. Il piano elenca l’impalcatura, e l’importazione la rimuove dopo che hai confermato il piano.
- Ogni lingua usata dal pacchetto. Aggiungi ciascuna lingua del pacchetto alla configurazione i18n della destinazione. Un sito senza configurazione i18n accetta solo
en. Le lingue vengono confrontate senza distinguere tra maiuscole e minuscole, e l’importazione scrive ogni lingua con la grafia configurata nella destinazione, dichiarandola comelocale_recased. - Un limite di caricamento sufficientemente grande. Ogni file multimediale deve rientrare nel
maxUploadSizedella destinazione, che per impostazione predefinita è di 50 MiB. - Versione del formato
1. La destinazione deve supportare la versione del formato del pacchetto e ogni funzionalità richiesta.
La richiesta seguente restituisce le versioni del formato, le funzionalità e i limiti supportati. Il suo oggetto portableDomain indica se il sito può ricevere un’importazione e, in caso contrario, il motivo.
curl https://new.example.com/_emdash/api/admin/transfer/capabilities \
-H "Authorization: Bearer $EMDASH_TOKEN"
Esportare un sito
Un’esportazione legge il sito in passaggi limitati e scrive il pacchetto nell’archiviazione del sito. Prima che un’esportazione termini, l’esportatore convalida il pacchetto completato nello stesso modo di un’importazione. Quando una scrittura sul sito va a buon fine durante un’esportazione, l’esportatore ricomincia. Acquisire o rinnovare un blocco di modifica su una voce non conta come scrittura. Dopo tre tentativi, fallisce con TRANSFER_EXPORT_CONCURRENT_WRITES.
I file dell’esportazione restano disponibili per sette giorni dalla sua creazione. Trascorso questo periodo, un download restituisce TRANSFER_EXPIRED.
Esportare dall’amministrazione
-
Apri Settings → Transfer. La pagina è disponibile per gli amministratori.
-
Nella sezione Export, disattiva Include comments per escludere commenti e reazioni.
-
Seleziona Export site. La pagina mostra l’avanzamento dell’esportazione. Tieni la pagina aperta; se la lasci, l’esportazione riprende quando torni.
-
Quando compare Export ready, seleziona Download package e scegli dove salvare il file
.emdash. La pagina mostra quanti file e byte sono stati scaricati, e Stop annulla il download.
La sezione mostra anche il digest del pacchetto, il numero di record di ogni tipo e le esportazioni recenti del sito, ciascuna con il proprio pulsante di download fino alla scadenza.
Download package recupera l’esportazione un file alla volta, controlla dimensione e digest SHA-256 di ciascun file rispetto al manifest e crea il file .emdash nel browser, quindi funziona su Cloudflare Workers per siti di qualsiasi dimensione. Se un file non corrisponde, il download si interrompe con un errore. Chrome, Edge e gli altri browser basati su Chromium scrivono il file direttamente su disco. Gli altri browser mantengono l’intero pacchetto in memoria fino al termine del download; per un’esportazione superiore a circa 500 MB, la pagina consiglia un browser basato su Chromium o la CLI.
Download as one file chiede invece al server l’archivio in un’unica risposta. È adatto ai siti piccoli. Su Cloudflare Workers, un sito grande può superare i limiti di una singola richiesta.
Esportare con la CLI
Accedi al sito di origine, quindi esportalo in un file di pacchetto:
npx emdash login --url https://example.com
npx emdash site export --url https://example.com --output site.emdash
Il comando porta a termine l’esportazione, scarica il pacchetto file per file, controlla dimensione e digest di ciascun file e scrive site.emdash. Aggiungi --no-comments per escludere commenti e reazioni. Se il comando viene interrotto, eseguilo di nuovo con le stesse opzioni per riprendere la stessa esportazione. Consulta il riferimento di emdash site export.
Esportare con l’API REST
Ogni chiamata ad advance esegue un passaggio e restituisce nextRequestInMs, il ritardo prima della chiamata successiva. L’esportazione è terminata quando nextRequestInMs è null.
Questi esempi usano un token di accesso personale con l’ambito transfer:export. Consulta ambiti dei token.
-
Avvia l’esportazione. Per escludere commenti e reazioni, invia
{ "comments": false }come corpo. Un’intestazioneIdempotency-Keyfa sì che una richiesta ripetuta restituisca la stessa esportazione invece di avviarne un’altra. Riutilizzare una chiave con opzioni diverse fallisce con409 TRANSFER_IDEMPOTENCY_CONFLICT.curl -X POST https://example.com/_emdash/api/admin/transfer/exports \ -H "Authorization: Bearer $EMDASH_TOKEN" \ -H "Idempotency-Key: move-to-new-host" -
Fai avanzare l’esportazione finché
nextRequestInMsnon ènull. Attendi tra una chiamata e l’altra il numero di millisecondi restituito.operation.progressriporta i passaggidoneetotal, irecordsscritti finora ebytesDoneebytesTotaluna volta nota la dimensione del pacchetto.curl -X POST https://example.com/_emdash/api/admin/transfer/exports/$EXPORT_ID/advance \ -H "Authorization: Bearer $EMDASH_TOKEN" -
Verifica che
operation.statesiacomplete. Un’esportazionefailedriporta il motivo inoperation.errorCode. -
Scarica il pacchetto come un unico file
.emdash:curl -o site.emdash \ https://example.com/_emdash/api/admin/transfer/exports/$EXPORT_ID/archive \ -H "Authorization: Bearer $EMDASH_TOKEN"
Un file .emdash è un archivio tar non compresso con manifest.json come prima voce. L’archivio trasmette tutti i file in un’unica risposta. Su Cloudflare Workers, un sito grande può superare i limiti di una singola richiesta. In tal caso scarica manifest.json da exports/{id}/manifest e ciascun file da exports/{id}/files/{path}. Ogni file scaricato viene controllato rispetto al digest registrato durante la trasmissione. Se i byte archiviati sono cambiati dopo l’esportazione, il download termina con un errore invece di completarsi.
Importare un sito
Un’importazione viene creata da un pacchetto, analizzata per produrre un piano ed eseguita solo dopo che hai confermato quel piano tramite il suo digest. Un’importazione la cui esecuzione non è ancora iniziata scade 24 ore dopo la creazione.
L’amministrazione, la CLI e l’API REST possono eseguire ogni passaggio. Un agente IA può analizzare e avviare un’importazione già caricata, tramite gli strumenti MCP.
Importare dall’amministrazione
-
Sul sito di destinazione, apri Settings → Transfer. La sezione Import compare quando il sito può ricevere un’importazione. Altrimenti elenca ciò che il sito contiene già e che impedisce l’importazione.
-
Seleziona Choose package file e scegli il file
.emdash. Il browser controlla il pacchetto e lo carica in parti. Durante il caricamento sul sito non cambia nulla. Se il caricamento si interrompe, scegli di nuovo lo stesso file per riprendere da dove si era fermato. -
Al termine del caricamento, il sito analizza il pacchetto. Puoi lasciare la pagina e tornare più tardi.
-
Esamina l’importazione: il sito di origine, la data di esportazione e la versione di EmDash, la dimensione, il digest del pacchetto e il numero di record di ogni tipo. Leggi i Blockers e i Warnings, le Differences from the source site, che elencano le trasformazioni del piano, e lo Starter content that will be removed, raggruppato per tipo. Consulta esaminare il piano di importazione.
-
In Authors, scegli l’utente di questo sito a cui deve appartenere il contenuto di ciascun autore, oppure Don’t map. Gli autori che corrispondono all’indirizzo email di un utente sono contrassegnati come Matched by email. Consulta associare gli autori agli utenti di destinazione.
-
In Site identity, scegli se usare il titolo e lo slogan del sito del pacchetto o mantenere quelli di questo sito.
-
Seleziona Start import e conferma. Il pulsante è disattivato finché il piano contiene blocchi. La modifica sul sito resta sospesa fino al termine dell’importazione.
-
Segui l’avanzamento. Al termine dell’importazione, la pagina mostra la ricevuta con un badge Verified e i relativi digest di ricevuta, pacchetto, piano e contenuto. Seleziona Copy receipt per conservare una copia del JSON della ricevuta.
La pagina offre anche Cancel import dal caricamento fino al termine dell’importazione, e Abandon import dopo che un’importazione che aveva iniziato a scrivere è fallita o è stata annullata. Entrambe chiedono una conferma. Consulta annullare un’importazione e abbandonare un’importazione incompleta.
Importare con la CLI
Accedi al sito di destinazione, quindi analizza il pacchetto:
npx emdash login --url https://new.example.com
npx emdash site import site.emdash --url https://new.example.com --analyze
Il comando controlla localmente l’intero file del pacchetto, lo carica, lo analizza e stampa il piano con il relativo digest del piano. Termina con il codice 2 quando il piano contiene blocchi. Esamina il piano come descritto in esaminare il piano di importazione.
Per modificare le decisioni del piano, esegui di nuovo --analyze con i flag di decisione. --map-principal associa un principal, per ID o indirizzo email, a un utente di destinazione per ID o indirizzo email, oppure a none. --use-target-title e --use-target-tagline mantengono il titolo e lo slogan della destinazione:
npx emdash site import site.emdash --url https://new.example.com --analyze \
--map-principal [email protected][email protected] \
--map-principal 01J8ZQ4Y6T2N0D3VJ5R7K9M1PX=none \
--use-target-title
Esegui il piano che hai esaminato passando il suo digest:
npx emdash site import site.emdash --url https://new.example.com \
--plan sha256:3f1c… --confirm
Il comando porta a termine l’importazione e stampa la ricevuta. Se viene interrotto, riprendilo con emdash site import resume <operation-id>. emdash site import status <operation-id> stampa lo stato dell’importazione, ed emdash site import receipt <operation-id> stampa di nuovo la ricevuta. Consulta il riferimento di emdash site import.
Importare con l’API REST
Il server lavora con i file contenuti in un pacchetto, non con l’archivio .emdash. Estrai prima l’archivio. Contiene manifest.json, file di indice in index/, file di record in records/ e file multimediali in media/. Il manifest fissa la dimensione e il digest SHA-256 di ogni file, quindi il digest del pacchetto identifica l’intero pacchetto.
Questi esempi usano un token con gli ambiti transfer:analyze e transfer:execute.
-
Crea l’importazione. Invia i byte invariati di
manifest.jsoncome corpo della richiesta. La risposta contiene l’operazione e la prima pagina dei file di cui il server ha ancora bisogno.curl -X POST https://new.example.com/_emdash/api/admin/transfer/imports \ -H "Authorization: Bearer $EMDASH_TOKEN" \ -H "Idempotency-Key: move-to-new-host" \ --data-binary @site/manifest.json -
Carica ogni file mancante in
imports/{id}/files/{path}. L’intestazioneContent-Lengthdeve essere uguale alla dimensione dichiarata del file, e i byte devono corrispondere al digest dichiarato.curl -X PUT \ https://new.example.com/_emdash/api/admin/transfer/imports/$IMPORT_ID/files/index/000000.ndjson \ -H "Authorization: Bearer $EMDASH_TOKEN" \ --data-binary @site/index/000000.ndjsonIl caricamento di un file di indice dichiara i file di record e multimediali che elenca. Richiedi di nuovo
imports/{id}/missingdopo ogni gruppo di caricamenti e continua finché non restituisce più alcun elemento.Il caricamento di un file già archiviato lo controlla di nuovo. Se la copia archiviata non corrisponde più, il caricamento la sostituisce e la risposta riporta
alreadyVerified: false. -
Analizza il pacchetto. Chiama
imports/{id}/analyzefinchénextRequestInMsnon ènull. La risposta finale contiene ilplane il suoplanDigest.curl -X POST https://new.example.com/_emdash/api/admin/transfer/imports/$IMPORT_ID/analyze \ -H "Authorization: Bearer $EMDASH_TOKEN" -
Esamina il piano e leggi ogni blocco, avviso e trasformazione. Consulta esaminare il piano di importazione.
-
Invia le decisioni se i valori predefiniti non sono quelli che desideri. Ogni invio restituisce un nuovo piano e un nuovo digest del piano. Una volta richiesta l’esecuzione, il piano viene congelato e l’invio di decisioni fallisce con
409 TRANSFER_INVALID_STATE.curl -X POST https://new.example.com/_emdash/api/admin/transfer/imports/$IMPORT_ID/analyze \ -H "Authorization: Bearer $EMDASH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "decisions": { "principalMappings": { "01J8ZQ4Y6T2N0D3VJ5R7K9M1PX": null }, "siteTitle": "target" } }' -
Avvia l’importazione con i digest che hai esaminato:
curl -X POST https://new.example.com/_emdash/api/admin/transfer/imports/$IMPORT_ID/execute \ -H "Authorization: Bearer $EMDASH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "packageDigest": "sha256:…", "planDigest": "sha256:…" }' -
Fai avanzare l’importazione finché
nextRequestInMsnon ènull, attendendo tra una chiamata e l’altra il ritardo restituito.curl -X POST https://new.example.com/_emdash/api/admin/transfer/imports/$IMPORT_ID/advance \ -H "Authorization: Bearer $EMDASH_TOKEN" -
Verifica che
operation.statesiacomplete, quindi leggi la ricevuta daimports/{id}/receipt.
L’esecuzione fallisce con TRANSFER_PACKAGE_DIGEST_MISMATCH o TRANSFER_PLAN_DIGEST_MISMATCH quando uno dei due digest differisce dal pacchetto caricato o dal piano corrente. Leggi il piano corrente da imports/{id}/plan, esaminalo di nuovo e riprova con i suoi digest.
Associare gli autori agli utenti di destinazione
L’analisi elenca ogni principal con il nome visualizzato, l’indirizzo email e il numero di record del pacchetto che vi fanno riferimento. Quando esattamente un utente di destinazione ha lo stesso indirizzo email, confrontato senza distinguere tra maiuscole e minuscole, il piano suggerisce quell’utente e vi associa il principal per impostazione predefinita. I principal senza suggerimento partono senza associazione.
Per modificare un’associazione, passa --map-principal a emdash site import --analyze, oppure invia principalMappings all’endpoint di analisi. Ogni associazione indica un utente di destinazione o lascia il principal senza associazione (none nella CLI, null nell’API). EmDash applica ogni associazione agli autori delle voci, agli autori delle revisioni, a chi ha caricato i media, ai collegamenti utente delle byline e agli autori dei commenti.
I riferimenti di un principal senza associazione vengono rimossi. Quando un autore senza associazione aveva anche una byline collegata al proprio account, l’importatore attribuisce esplicitamente quella byline a ciascuna voce dell’autore che non ha un credito di byline esplicito e la cui lingua possiede la byline dell’autore. Il credito dell’autore resta quindi sulla pagina.
Due associazioni producono un blocco principal_conflict:
- un principal con più di una byline nella stessa lingua viene associato a un utente; oppure
- due principal che hanno entrambi byline nella stessa lingua vengono associati allo stesso utente.
Un utente di destinazione può avere una sola byline per lingua. Lascia un principal senza associazione, oppure associa i principal a utenti diversi.
Esaminare il piano di importazione
Un piano elenca ciò che l’importazione creerà, le decisioni che applicherà e tre tipi di rilevamenti:
- I blocchi impediscono l’esecuzione. L’esecuzione restituisce
TRANSFER_PLAN_BLOCKEDfinché il piano ne contiene. Modifica le associazioni dei principal per risolvere unprincipal_conflict. Qualsiasi altro blocco richiede una modifica al pacchetto o alla destinazione: annulla l’importazione, apporta la modifica e crea una nuova importazione. - Gli avvisi descrivono problemi del pacchetto che non interrompono l’importazione. Vengono copiati nella ricevuta.
- Le trasformazioni sono le differenze esatte e dichiarate tra il sito di origine e il sito importato. Le modifiche dell’esportatore sono elencate per prime, poi quelle dell’importazione. La verifica applica le trasformazioni dell’importazione quando confronta il sito importato con il pacchetto.
Un piano elenca al massimo 500 blocchi e avvisi. Un avviso issues_truncated indica quanti altri ne sono stati trovati.
Blocchi
| Codice | Significato |
|---|---|
package_invalid | Un file o un percorso del pacchetto non supera la convalida. |
unsupported_format | La destinazione non supporta il formato o la versione del formato del pacchetto. |
unsupported_feature | Il pacchetto richiede una funzionalità che la destinazione non supporta. |
limit_exceeded | Un file o un record del pacchetto supera un limite. |
file_missing | Un file dichiarato del pacchetto non è stato caricato. |
file_mismatch | La dimensione o il digest di un file del pacchetto non corrisponde alla sua dichiarazione. |
record_invalid | Un record non è ben formato o non è JSON canonico. |
record_count_mismatch | Il numero di record di un tipo differisce dal manifest. |
record_order_invalid | I record non sono in ordine, oppure un elemento padre compare dopo il proprio figlio. |
duplicate_id | Due record dello stesso tipo condividono un ID. |
dangling_reference | Un record fa riferimento a un record che non è nel pacchetto. Ciò include un campo blocchi che nomina un tipo di blocco assente dal pacchetto, e un tipo di blocco la cui versione corrente è assente dal pacchetto. |
reference_cycle | Un termine, un commento o una voce di menu è padre di se stesso. |
media_ref_invalid | Il contenuto fa riferimento a un record multimediale che non è nel pacchetto. |
media_blob_missing | Il file di un record multimediale non è nel pacchetto. |
media_blob_too_large | Un file multimediale è più grande del maxUploadSize della destinazione. |
target_not_empty | La destinazione contiene già dei contenuti. Il detail del blocco indica cosa è stato trovato. |
locale_not_configured | Il pacchetto usa una lingua che la configurazione i18n della destinazione non include. |
field_type_unknown | Un campo o un campo byline usa un tipo che la destinazione non supporta. |
principal_conflict | Le associazioni dei principal darebbero a un utente due byline nella stessa lingua. |
integer_out_of_range | Un intero è al di fuori dell’intervallo di interi del database di destinazione. PostgreSQL memorizza gli interi a 32 bit. |
value_constraint_violation | Un valore che l’API di amministrazione rifiuterebbe. Consulta l’elenco seguente. |
unique_violation | Un record duplicherebbe la chiave univoca di un altro record nella destinazione. |
L’importatore scrive direttamente i record, quindi l’analisi applica gli stessi controlli che l’API di amministrazione applica quando quei record vengono salvati. Ciascuno di questi valori è una value_constraint_violation:
- un valore di voce che non rientra nella colonna del suo campo, un campo obbligatorio senza valore o un valore per un campo che la collezione non ha;
- un reindirizzamento la cui origine o destinazione non è un percorso del sito, il cui tipo non è supportato, il cui pattern di origine non è valido o la cui destinazione usa un parametro che l’origine non cattura;
- un sito web della byline che non è un URL
httpohttps, un valore di campo byline che non corrisponde al tipo o alle scelte del suo campo, oppure un campo byline con più scelte di quante un sito ne supporti; - un pattern di URL della collezione non valido;
- un tipo di blocco con uno slug riservato, un’etichetta vuota o più lunga di 200 caratteri, oppure definizioni di campi che l’editor dei tipi di blocco rifiuterebbe;
- un URL canonico SEO che non è né un URL
httpohttpsné un percorso del sito; e - un URL di voce di menu con uno schema che i menu non consentono.
Avvisi
| Codice | Significato |
|---|---|
media_provider_external | Il contenuto usa media di un provider esterno. Il riferimento viene mantenuto; i file non vengono copiati. |
media_row_missing | Un’impostazione fa riferimento a media che non sono nel pacchetto. |
soft_reference_dangling | Un riferimento facoltativo non si risolve in un record del pacchetto. |
redirect_loops_unchecked | Il pacchetto contiene troppi reindirizzamenti per controllare i loop prima dell’importazione. Un reindirizzamento che chiuderebbe un loop viene importato disattivato. |
issues_truncated | Sono stati trovati più blocchi o avvisi di quanti il piano ne elenchi. |
Trasformazioni
L’esportatore dichiara le modifiche che ha apportato ai dati del sito di origine. Ciascuna di queste trasformazioni riporta un tipo di record e un conteggio:
| Codice | Significato |
|---|---|
orphan_dropped | Sono stati esclusi record il cui elemento padre non esisteva più sul sito di origine, come una revisione di una voce eliminata. |
soft_orphan_dropped | Sono stati esclusi collegamenti a record mancanti, come l’assegnazione di un termine eliminato o una voce di menu che punta a una voce eliminata. |
orphan_reference_nulled | È stato rimosso un riferimento a un record mancante, come la cartella eliminata di un file multimediale. |
avatar_nulled | Un avatar della byline o un’immagine di anteprima di una sezione faceva riferimento a media non presenti nel pacchetto ed è stato rimosso. |
media_not_ready_dropped | Sono stati esclusi media non pronti, come un caricamento incompleto. |
media_ref_unlinked | Sono stati rimossi dal contenuto i riferimenti a media non presenti nel pacchetto. |
media_url_relativized | Gli URL assoluti verso i file multimediali del sito di origine sono stati convertiti in URL relativi al sito che si risolvono nella destinazione. |
redirect_duplicate_dropped | Sono stati esclusi reindirizzamenti duplicati per lo stesso percorso di origine. È stato mantenuto un reindirizzamento per ogni percorso di origine. |
unknown_storage_key | Alcuni record fanno ancora riferimento a file multimediali che il sito di origine non possiede. Sono stati esportati senza modifiche. |
L’importazione dichiara le proprie modifiche:
| Codice | Significato |
|---|---|
principal_mapped | I riferimenti ai principal vengono riscritti verso gli utenti di destinazione associati. |
principal_unmapped | I riferimenti ai principal senza associazione vengono rimossi. |
seeded_scaffold_removed | L’impalcatura di configurazione della destinazione viene eliminata prima che l’importazione scriva. Il piano elenca ogni elemento. |
redirect_loop_disabled | I reindirizzamenti che formano un loop vengono importati disattivati. |
search_unsupported | La ricerca viene disattivata per le collezioni elencate perché la destinazione usa PostgreSQL. |
float4_rounded | I valori decimali vengono arrotondati alla precisione delle colonne real di PostgreSQL della destinazione. |
locale_recased | Le lingue vengono scritte con la grafia configurata nella destinazione, ad esempio pt-br come pt-BR. |
Eseguire l’importazione
L’esecuzione attraversa queste fasi, nell’ordine:
- Riservare la destinazione e verificare di nuovo che sia vuota.
- Rimuovere l’impalcatura di configurazione elencata nel piano.
- Creare tipi di blocco, collezioni, campi, definizioni di tassonomie, definizioni di relazioni e campi byline.
- Copiare i file multimediali nell’archiviazione della destinazione e creare i record multimediali.
- Scrivere termini e byline.
- Scrivere revisioni e voci.
- Scrivere assegnazioni di termini, crediti delle byline, riferimenti ai contenuti e record SEO.
- Scrivere menu, widget, sezioni, reindirizzamenti, commenti, reazioni e impostazioni.
- Ricostruire gli indici di ricerca e le cache, e mettere in coda la reindicizzazione dell’utilizzo dei media.
- Verificare il risultato.
Ogni chiamata ad advance esegue un passaggio limitato, che rientra nei limiti di richiesta di Cloudflare Workers su D1. L’avanzamento viene memorizzato sul server. Una richiesta interrotta perde al massimo il passaggio in corso, e ogni scrittura è idempotente, quindi eseguire di nuovo un passaggio non duplica i record.
Mentre un’altra richiesta sta eseguendo un passaggio, o quando un’altra richiesta prende in carico l’operazione durante un passaggio, advance restituisce l’operazione con un nextRequestInMs breve. Un errore di archiviazione o di database viene ritentato: l’operazione registra l’errore e nextRequestInMs aumenta a ogni errore consecutivo. Dopo errori ripetuti senza avanzamento, l’importazione fallisce.
Le scritture sono bloccate durante un’importazione
Dal primo passaggio di esecuzione fino al completamento dell’importazione, EmDash rifiuta le richieste di scrittura alla propria API con 503 TRANSFER_IMPORT_IN_PROGRESS. Ciò riguarda l’amministrazione, l’API REST, le route dei plugin, l’invio pubblico di commenti, la pubblicazione programmata e le scritture di contenuti da parte dei plugin. L’accesso, la gestione di utenti e token API, i blocchi di modifica delle voci e la stessa API di trasferimento restano disponibili. Le richieste di lettura non vengono bloccate.
Gli strumenti MCP di scrittura, inclusi gli strumenti MCP dei plugin, falliscono con TRANSFER_IMPORT_IN_PROGRESS nel consueto errore dello strumento. Gli strumenti MCP di sola lettura e gli strumenti di trasferimento site_* continuano a funzionare, quindi un’importazione avviata tramite MCP può essere ripresa, ispezionata e completata tramite MCP.
Riprendere dopo un’interruzione
La pagina di amministrazione fa avanzare un’importazione solo finché è aperta. Per riprendere, riapri Settings → Transfer, esegui emdash site import resume <operation-id> oppure chiama di nuovo advance per la stessa operazione. Il server riprende dall’ultimo passaggio completato. Se la richiesta interrotta deteneva ancora l’operazione, la chiamata successiva attende la scadenza di quella detenzione, al massimo cinque minuti.
Un’importazione fallita o annullata non può essere ripresa.
Annullare un’importazione
Seleziona Cancel import in Settings → Transfer, esegui emdash site import cancel <operation-id> oppure invia POST imports/{id}/cancel. Un passaggio in corso si interrompe dopo il gruppo corrente. L’annullamento non rimuove i record già scritti.
Abbandonare un’importazione incompleta
Un’importazione fallita o annullata che aveva iniziato a scrivere continua a bloccare le scritture, in modo che il sito incompleto non possa essere modificato per errore. Per rimuovere il blocco, seleziona Abandon import in Settings → Transfer, esegui emdash site import abandon <operation-id> oppure invia POST imports/{id}/abandon. L’abbandono conserva i dati importati.
Dopo un abbandono, il sito non è più vuoto, quindi non può ricevere un’altra importazione. Importa invece in un sito appena configurato.
Un’importazione fallita o annullata che non ha mai iniziato a scrivere non blocca le scritture e non deve essere abbandonata.
Verificare il risultato
La verifica rilegge ogni record importato con lo stesso codice usato dall’esportatore, applica ai record del pacchetto le trasformazioni dichiarate nel piano e confronta i due risultati. Controlla anche il conteggio dei record di ogni tipo e scarica di nuovo ogni file multimediale importato per verificarne il digest. Qualsiasi differenza fa fallire l’importazione con TRANSFER_VERIFICATION_FAILED. L’errorDetail dell’operazione elenca fino a 50 differenze.
Un’importazione riuscita produce una ricevuta:
{
"operationId": "01J8ZR2C4S6D8F0G2H4J6K8M0N",
"packageDigest": "sha256:…",
"planDigest": "sha256:…",
"targetSiteId": "01J8ZR0A2B4C6D8E0F2G4H6J8K",
"originSiteId": "01J1A3C5E7G9J1L3N5Q7S9U1W3",
"formatVersion": "1",
"importerEmDashVersion": "0.38.0",
"completedAt": "2026-09-23T10:15:00.000Z",
"logicalDigest": "sha256:…",
"counts": { "entry": 412, "media": 96 },
"warnings": [],
"verification": "verified",
"receiptDigest": "sha256:…"
}
Una ricevuta attesta che il sito di destinazione identificato da targetSiteId conteneva esattamente il contenuto del pacchetto identificato da packageDigest, dopo il piano identificato da planDigest, al termine della verifica. Il logicalDigest riassume i record verificati.
receiptDigest è il digest SHA-256 del JSON canonico della ricevuta senza la proprietà receiptDigest. Rileva una ricevuta modificata dopo l’emissione. Una ricevuta non è firmata, quindi non dimostra quale server l’abbia emessa. Quando è importante, recupera la ricevuta dalla destinazione tramite una connessione autenticata.
Una ricevuta descrive il sito nel momento in cui la verifica è terminata. Non dice nulla sulle modifiche successive.
Spostarsi tra database
Un pacchetto non dipende dal database dell’origine. Esporta da SQLite, PostgreSQL o D1 e importa in uno qualsiasi di essi. Tieni conto delle seguenti differenze quando la destinazione usa PostgreSQL:
- PostgreSQL memorizza gli interi a 32 bit. Un intero al di fuori di questo intervallo è un blocco
integer_out_of_range. - PostgreSQL memorizza i campi
numbere i punti focali dei media come valori in virgola mobile a 32 bit. I valori che cambiano vengono dichiarati comefloat4_rounded, e la verifica confronta i valori arrotondati. - La ricerca full-text è disponibile solo su SQLite e D1. Le collezioni con la ricerca attivata vengono importate con la ricerca disattivata e dichiarate come
search_unsupported.
L’importatore scrive i media nel backend di archiviazione della destinazione con nuove chiavi di archiviazione e riscrive di conseguenza i riferimenti ai media nei contenuti, nelle impostazioni e nei record SEO. Un riferimento a un file multimediale che l’origine non possiede viene esportato senza modifiche e dichiarato come unknown_storage_key.
Sicurezza
- Tratta un pacchetto come sensibile. Contiene tutti i contenuti, incluse bozze e cestino, e gli indirizzi email di autori e commentatori. Tienilo lontano da bucket pubblici e cartelle condivise, ed elimina le copie che non ti servono più.
- Tratta un pacchetto come input non attendibile. L’importazione controlla percorsi, dimensioni, digest, schemi dei record, riferimenti e limiti prima di scrivere. Non esegue mai codice o SQL provenienti da un pacchetto e non recupera mai URL contenuti in esso.
- Concedi l’accesso al trasferimento in modo ponderato. Il trasferimento richiede il ruolo di amministratore. Un token con l’ambito
adminpuò eseguire ogni azione di trasferimento, quindi concedi al token di un agente solo l’ambito di trasferimento di cui ha bisogno. - Esamina il log di audit. EmDash registra le azioni di trasferimento nel log di audit del sito:
transfer_export_create,transfer_import_create,transfer_import_execute,transfer_import_cancel,transfer_import_abandon,transfer_import_complete,transfer_import_fail,transfer_approval_approveetransfer_approval_deny. Ogni voce indica l’utente che ha agito e l’operazione o l’approvazione (tipo di risorsatransfer_operationotransfer_approval). I suoi dettagli contengono solo ID, digest, conteggi dei record e codici di errore, mai contenuti del pacchetto. Allo stesso modo, i dettagli degli errori di trasferimento non includono mai contenuti del pacchetto. - Mantieni privata l’area di staging. EmDash deposita i file del pacchetto sotto il prefisso
transfers/del tuo bucket di archiviazione e si rifiuta di servire quel prefisso tramite la sua route dei media. Se il bucket ha un dominio pubblico, limitalo ai media, come per i backup. I file in staging vengono eliminati quando un’operazione termina o scade.
Ambiti dei token
Il trasferimento usa tre ambiti di token API:
| Ambito | Consente |
|---|---|
transfer:export | Avviare, far avanzare e scaricare le esportazioni. |
transfer:analyze | Creare importazioni, caricare file del pacchetto, analizzare e leggere i piani. |
transfer:execute | Avviare, far avanzare, annullare e abbandonare le importazioni. |
L’ambito admin li include tutti e tre, quindi il token salvato da emdash login può eseguire qualsiasi trasferimento. Ogni ambito di trasferimento concede solo le proprie azioni, e solo un amministratore può emetterne uno. Usali per dare a un token un accesso più ristretto di admin, ad esempio a un agente che può analizzare i pacchetti ma non esportare né importare. Consulta il riferimento degli ambiti.
Approvazioni per gli agenti
Gli agenti IA gestiscono i trasferimenti tramite gli strumenti MCP site_*. Gli strumenti avviano le operazioni, le fanno avanzare e ne riportano lo stato. Non trasportano mai i byte del pacchetto, quindi l’utente di un agente scarica le esportazioni e carica i pacchetti con la CLI o l’API REST. Ogni strumento richiede il ruolo Admin.
Un client MCP il cui token non ha né admin né l’ambito di trasferimento corrispondente, come un agente a cui è stato concesso solo transfer:analyze, non può avviare da solo un’esportazione o un’importazione. La sua chiamata a site_export_start o site_import_start crea una richiesta di approvazione in sospeso e fallisce con TRANSFER_APPROVAL_REQUIRED e l’ID dell’approvazione. Un amministratore approva o rifiuta la richiesta in Approval requests all’interno di Settings → Transfer, che elenca ogni richiesta in sospeso con il richiedente, l’azione e l’orario di scadenza. Gli endpoint riservati alle sessioni POST /_emdash/api/admin/transfer/approvals/{id}/approve e …/deny fanno lo stesso. I token API non possono approvare le richieste. Il client ripete quindi la chiamata con l’ID dell’approvazione. Le approvazioni si applicano solo a questi strumenti MCP; l’API REST non ha un parametro di approvazione.
Un’approvazione concede una chiamata all’utente che l’ha richiesta, dallo stesso token e con gli stessi argomenti. Un’approvazione di esportazione è vincolata alle opzioni di esportazione. Un’approvazione di importazione è vincolata all’operazione e a entrambi i digest, quindi un piano modificato richiede una nuova approvazione. Una richiesta in sospeso scade dopo 15 minuti, e una approvata 15 minuti dopo l’approvazione. Il nuovo tentativo che avvia l’operazione la consuma; se l’operazione non si avvia, la stessa approvazione può essere ritentata fino alla scadenza. Lo stesso utente e lo stesso token possono poi controllare e far avanzare quell’unica operazione senza l’ambito.
Concedi transfer:export, transfer:execute o admin al token di un agente solo quando l’agente deve eseguire trasferimenti senza che una persona approvi ciascuno di essi.
Limiti
| Limite | Valore |
|---|---|
manifest.json | 8 MiB |
| Un record | 1.900.000 byte |
| Un file di record o di indice | 4 MiB e 1.000 record |
| Record per pacchetto | 5.000.000 |
| File per pacchetto | 1.000.000 |
| Profondità di annidamento JSON | 64 |
| Un file multimediale | Il maxUploadSize della destinazione, 50 MiB per impostazione predefinita |
L’endpoint capabilities riporta i valori applicati dal sito.
Per i provider di hosting
Un piano di controllo di hosting può portare in produzione il sito di un cliente usando solo l’API REST:
-
Effettua il provisioning di un nuovo sito EmDash con la relativa archiviazione, le lingue e il
maxUploadSize, e completa la configurazione. Verifica checapabilitiesriportiportableDomain.emptycometrue. -
Emetti un token per il piano di controllo con
transfer:analyzeetransfer:execute. Tienilo lontano da qualsiasi agente o strumento di creazione di siti. -
Esegui l’importazione e applica la tua politica agli avvisi del piano prima di eseguirla. Rifiuta qualsiasi piano con blocchi.
-
Recupera la ricevuta e controllala prima di promuovere il sito:
verificationèverified;packageDigestè il digest del pacchetto che intendevi pubblicare;planDigestè il piano che hai accettato;targetSiteIdè il sito che stai per promuovere; ereceiptDigestcorrisponde al JSON canonico della ricevuta.
-
Promuovi il sito, ad esempio indirizzando il suo dominio verso di esso.
Mantieni la destinazione irraggiungibile finché il passaggio 4 non va a buon fine. EmDash non nasconde ai visitatori un sito parzialmente importato.
Risoluzione dei problemi
Gli errori di trasferimento usano codici stabili. Lo stato HTTP compare accanto a ciascun codice.
| Codice | Stato | Cosa fare |
|---|---|---|
TRANSFER_TARGET_NOT_EMPTY | 409 | La destinazione contiene già dei contenuti. Importa in un sito appena configurato. Settings → Transfer e capabilities elencano ciò che rende il sito non idoneo. |
TRANSFER_IMPORT_IN_PROGRESS | 503 | Su questo sito è in corso un’importazione, oppure un’importazione incompleta sta ancora bloccando le scritture. Attendi che termini, oppure abbandona un’importazione fallita o annullata. |
TRANSFER_FENCE_CHECK_FAILED | 503 | EmDash non è riuscito a verificare se è in corso un’importazione. Riprova la scrittura. |
TRANSFER_EXPORT_CONCURRENT_WRITES | 409 | Il sito ha continuato a cambiare durante l’esportazione. Esporta di nuovo quando l’attività di modifica è ridotta. |
TRANSFER_EXPIRED | 410 | I file dell’esportazione sono stati eliminati dopo sette giorni, oppure un’importazione non è stata eseguita entro 24 ore. Ricomincia. |
TRANSFER_FILE_MISSING | 422 | Alcuni file dichiarati non sono stati caricati. Carica tutto ciò che elenca imports/{id}/missing. |
TRANSFER_FILE_NOT_DECLARED | 422 | Il percorso di caricamento non è nel pacchetto. Carica solo i percorsi elencati. |
TRANSFER_FILE_SIZE_MISMATCH | 422 | Content-Length o i byte caricati differiscono dalla dimensione dichiarata. Carica il file senza modificarlo. |
TRANSFER_FILE_DIGEST_MISMATCH | 422 | I byte caricati differiscono dal digest dichiarato, oppure un file di esportazione è cambiato dopo l’esportazione. Carica il file originale o esporta di nuovo. |
TRANSFER_LIMIT_EXCEEDED | 413 | Un file supera un limite. Per i media, aumenta il maxUploadSize della destinazione. |
TRANSFER_MANIFEST_INVALID | 422 | Il corpo della richiesta non è un manifest valido. Invia manifest.json byte per byte. |
TRANSFER_UNSUPPORTED_FORMAT | 422 | Aggiorna EmDash sulla destinazione. |
TRANSFER_UNSUPPORTED_FEATURE | 422 | Aggiorna EmDash sulla destinazione. |
TRANSFER_CONTAINER_INVALID | 422 | Il file .emdash non è un archivio di pacchetto valido. Scaricalo di nuovo. |
TRANSFER_PLAN_BLOCKED | 409 | Il piano contiene blocchi. Consulta esaminare il piano di importazione. |
TRANSFER_PACKAGE_DIGEST_MISMATCH | 409 | Il digest non corrisponde al pacchetto caricato. Usa il packageDigest dell’operazione. |
TRANSFER_PLAN_DIGEST_MISMATCH | 409 | Il piano è cambiato da quando lo hai esaminato. Leggi il piano corrente ed esaminalo di nuovo. |
TRANSFER_DECISIONS_INVALID | 422 | Una decisione indica un principal sconosciuto o un utente di destinazione inesistente. Correggi l’associazione. |
TRANSFER_INVALID_STATE | 409 | L’operazione non si trova in uno stato che consente la richiesta. Leggi l’operazione e segui il suo state. |
TRANSFER_LEASE_ACTIVE | 409 | Un’altra richiesta sta eseguendo un passaggio. Attendi e riprova. |
TRANSFER_IDEMPOTENCY_CONFLICT | 409 | La Idempotency-Key è già stata usata per un’esportazione con altre opzioni o per un’importazione di un altro pacchetto. Usa una nuova chiave. |
TRANSFER_RUNTIME_MISMATCH | 409 | Una versione incompatibile di EmDash ha avviato l’operazione. Completala con la versione che l’ha avviata, oppure avviane una nuova. |
TRANSFER_VERIFICATION_FAILED | 422 | Il sito importato non corrisponde al pacchetto. Leggi le differenze in errorDetail, abbandona l’importazione e importa in un nuovo sito. |
TRANSFER_APPROVAL_REQUIRED | 403 | Un amministratore deve approvare la richiesta. Consulta approvazioni per gli agenti. |
TRANSFER_APPROVAL_INVALID | 403 | L’approvazione è sconosciuta, rifiutata, scaduta, già usata o vincolata ad altri parametri. Richiedine una nuova. |
TRANSFER_SCHEMA_UNCLASSIFIED | 500 | Il database contiene una tabella o una colonna che l’esportatore non riconosce. Esegui la versione di EmDash corrispondente alle migrazioni del database. |
INSUFFICIENT_SCOPE | 403 | Il token non ha né admin né l’ambito di trasferimento necessario alla richiesta. Emetti un token con quell’ambito. |