Trasferimento del sito

In questa pagina

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

MeccanismoScopoImportabileFile multimedialiUtenti e segreti
File seedInizializzare un modello dei contenuti e contenuti di esempioSì, con la semantica dei seedNoNo
Snapshot di anteprimaPopolare il rendering isolato delle anteprimeSolo anteprimaNoNo
Backup JSONIspezionare lo stato selezionato in forma di databaseNoNoNo
Backup grezzo di database e mediaRipristinare una distribuzioneRipristino nello stesso tipo di databaseCopia separataSì
Pacchetto del sitoSpostare un sito in un altro sito EmDashSì, in un sito vuotoSì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 come locale_recased.
  • Un limite di caricamento sufficientemente grande. Ogni file multimediale deve rientrare nel maxUploadSize della 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

  1. Apri Settings → Transfer. La pagina è disponibile per gli amministratori.

  2. Nella sezione Export, disattiva Include comments per escludere commenti e reazioni.

  3. Seleziona Export site. La pagina mostra l’avanzamento dell’esportazione. Tieni la pagina aperta; se la lasci, l’esportazione riprende quando torni.

  4. 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.

  1. Avvia l’esportazione. Per escludere commenti e reazioni, invia { "comments": false } come corpo. Un’intestazione Idempotency-Key fa sì che una richiesta ripetuta restituisca la stessa esportazione invece di avviarne un’altra. Riutilizzare una chiave con opzioni diverse fallisce con 409 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"
  2. Fai avanzare l’esportazione finché nextRequestInMs non è null. Attendi tra una chiamata e l’altra il numero di millisecondi restituito. operation.progress riporta i passaggi done e total, i records scritti finora e bytesDone e bytesTotal una 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"
  3. Verifica che operation.state sia complete. Un’esportazione failed riporta il motivo in operation.errorCode.

  4. 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

  1. 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.

  2. 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.

  3. Al termine del caricamento, il sito analizza il pacchetto. Puoi lasciare la pagina e tornare più tardi.

  4. 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.

  5. 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.

  6. In Site identity, scegli se usare il titolo e lo slogan del sito del pacchetto o mantenere quelli di questo sito.

  7. Seleziona Start import e conferma. Il pulsante è disattivato finché il piano contiene blocchi. La modifica sul sito resta sospesa fino al termine dell’importazione.

  8. 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 editor@example.com=editor@example.com \
  --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.

  1. Crea l’importazione. Invia i byte invariati di manifest.json come 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
  2. Carica ogni file mancante in imports/{id}/files/{path}. L’intestazione Content-Length deve 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.ndjson

    Il caricamento di un file di indice dichiara i file di record e multimediali che elenca. Richiedi di nuovo imports/{id}/missing dopo 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.

  3. Analizza il pacchetto. Chiama imports/{id}/analyze finché nextRequestInMs non è null. La risposta finale contiene il plan e il suo planDigest.

    curl -X POST https://new.example.com/_emdash/api/admin/transfer/imports/$IMPORT_ID/analyze \
      -H "Authorization: Bearer $EMDASH_TOKEN"
  4. Esamina il piano e leggi ogni blocco, avviso e trasformazione. Consulta esaminare il piano di importazione.

  5. 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" } }'
  6. 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:…" }'
  7. Fai avanzare l’importazione finché nextRequestInMs non è 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"
  8. Verifica che operation.state sia complete, quindi leggi la ricevuta da imports/{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_BLOCKED finché il piano ne contiene. Modifica le associazioni dei principal per risolvere un principal_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

CodiceSignificato
package_invalidUn file o un percorso del pacchetto non supera la convalida.
unsupported_formatLa destinazione non supporta il formato o la versione del formato del pacchetto.
unsupported_featureIl pacchetto richiede una funzionalità che la destinazione non supporta.
limit_exceededUn file o un record del pacchetto supera un limite.
file_missingUn file dichiarato del pacchetto non è stato caricato.
file_mismatchLa dimensione o il digest di un file del pacchetto non corrisponde alla sua dichiarazione.
record_invalidUn record non è ben formato o non è JSON canonico.
record_count_mismatchIl numero di record di un tipo differisce dal manifest.
record_order_invalidI record non sono in ordine, oppure un elemento padre compare dopo il proprio figlio.
duplicate_idDue record dello stesso tipo condividono un ID.
dangling_referenceUn 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_cycleUn termine, un commento o una voce di menu è padre di se stesso.
media_ref_invalidIl contenuto fa riferimento a un record multimediale che non è nel pacchetto.
media_blob_missingIl file di un record multimediale non è nel pacchetto.
media_blob_too_largeUn file multimediale è più grande del maxUploadSize della destinazione.
target_not_emptyLa destinazione contiene già dei contenuti. Il detail del blocco indica cosa è stato trovato.
locale_not_configuredIl pacchetto usa una lingua che la configurazione i18n della destinazione non include.
field_type_unknownUn campo o un campo byline usa un tipo che la destinazione non supporta.
principal_conflictLe associazioni dei principal darebbero a un utente due byline nella stessa lingua.
integer_out_of_rangeUn intero è al di fuori dell’intervallo di interi del database di destinazione. PostgreSQL memorizza gli interi a 32 bit.
value_constraint_violationUn valore che l’API di amministrazione rifiuterebbe. Consulta l’elenco seguente.
unique_violationUn 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 http o https, 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 http o https né un percorso del sito; e
  • un URL di voce di menu con uno schema che i menu non consentono.

Avvisi

CodiceSignificato
media_provider_externalIl contenuto usa media di un provider esterno. Il riferimento viene mantenuto; i file non vengono copiati.
media_row_missingUn’impostazione fa riferimento a media che non sono nel pacchetto.
soft_reference_danglingUn riferimento facoltativo non si risolve in un record del pacchetto.
redirect_loops_uncheckedIl pacchetto contiene troppi reindirizzamenti per controllare i loop prima dell’importazione. Un reindirizzamento che chiuderebbe un loop viene importato disattivato.
issues_truncatedSono 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:

CodiceSignificato
orphan_droppedSono stati esclusi record il cui elemento padre non esisteva più sul sito di origine, come una revisione di una voce eliminata.
soft_orphan_droppedSono 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_nulledUn 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_droppedSono stati esclusi media non pronti, come un caricamento incompleto.
media_ref_unlinkedSono stati rimossi dal contenuto i riferimenti a media non presenti nel pacchetto.
media_url_relativizedGli 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_droppedSono stati esclusi reindirizzamenti duplicati per lo stesso percorso di origine. È stato mantenuto un reindirizzamento per ogni percorso di origine.
unknown_storage_keyAlcuni 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:

CodiceSignificato
principal_mappedI riferimenti ai principal vengono riscritti verso gli utenti di destinazione associati.
principal_unmappedI riferimenti ai principal senza associazione vengono rimossi.
seeded_scaffold_removedL’impalcatura di configurazione della destinazione viene eliminata prima che l’importazione scriva. Il piano elenca ogni elemento.
redirect_loop_disabledI reindirizzamenti che formano un loop vengono importati disattivati.
search_unsupportedLa ricerca viene disattivata per le collezioni elencate perché la destinazione usa PostgreSQL.
float4_roundedI valori decimali vengono arrotondati alla precisione delle colonne real di PostgreSQL della destinazione.
locale_recasedLe 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:

  1. Riservare la destinazione e verificare di nuovo che sia vuota.
  2. Rimuovere l’impalcatura di configurazione elencata nel piano.
  3. Creare tipi di blocco, collezioni, campi, definizioni di tassonomie, definizioni di relazioni e campi byline.
  4. Copiare i file multimediali nell’archiviazione della destinazione e creare i record multimediali.
  5. Scrivere termini e byline.
  6. Scrivere revisioni e voci.
  7. Scrivere assegnazioni di termini, crediti delle byline, riferimenti ai contenuti e record SEO.
  8. Scrivere menu, widget, sezioni, reindirizzamenti, commenti, reazioni e impostazioni.
  9. Ricostruire gli indici di ricerca e le cache, e mettere in coda la reindicizzazione dell’utilizzo dei media.
  10. 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 number e i punti focali dei media come valori in virgola mobile a 32 bit. I valori che cambiano vengono dichiarati come float4_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 admin può 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_approve e transfer_approval_deny. Ogni voce indica l’utente che ha agito e l’operazione o l’approvazione (tipo di risorsa transfer_operation o transfer_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:

AmbitoConsente
transfer:exportAvviare, far avanzare e scaricare le esportazioni.
transfer:analyzeCreare importazioni, caricare file del pacchetto, analizzare e leggere i piani.
transfer:executeAvviare, 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

LimiteValore
manifest.json8 MiB
Un record1.900.000 byte
Un file di record o di indice4 MiB e 1.000 record
Record per pacchetto5.000.000
File per pacchetto1.000.000
Profondità di annidamento JSON64
Un file multimedialeIl 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:

  1. Effettua il provisioning di un nuovo sito EmDash con la relativa archiviazione, le lingue e il maxUploadSize, e completa la configurazione. Verifica che capabilities riporti portableDomain.empty come true.

  2. Emetti un token per il piano di controllo con transfer:analyze e transfer:execute. Tienilo lontano da qualsiasi agente o strumento di creazione di siti.

  3. Esegui l’importazione e applica la tua politica agli avvisi del piano prima di eseguirla. Rifiuta qualsiasi piano con blocchi.

  4. 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; e
    • receiptDigest corrisponde al JSON canonico della ricevuta.
  5. 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.

CodiceStatoCosa fare
TRANSFER_TARGET_NOT_EMPTY409La 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_PROGRESS503Su 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_FAILED503EmDash non è riuscito a verificare se è in corso un’importazione. Riprova la scrittura.
TRANSFER_EXPORT_CONCURRENT_WRITES409Il sito ha continuato a cambiare durante l’esportazione. Esporta di nuovo quando l’attività di modifica è ridotta.
TRANSFER_EXPIRED410I file dell’esportazione sono stati eliminati dopo sette giorni, oppure un’importazione non è stata eseguita entro 24 ore. Ricomincia.
TRANSFER_FILE_MISSING422Alcuni file dichiarati non sono stati caricati. Carica tutto ciò che elenca imports/{id}/missing.
TRANSFER_FILE_NOT_DECLARED422Il percorso di caricamento non è nel pacchetto. Carica solo i percorsi elencati.
TRANSFER_FILE_SIZE_MISMATCH422Content-Length o i byte caricati differiscono dalla dimensione dichiarata. Carica il file senza modificarlo.
TRANSFER_FILE_DIGEST_MISMATCH422I 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_EXCEEDED413Un file supera un limite. Per i media, aumenta il maxUploadSize della destinazione.
TRANSFER_MANIFEST_INVALID422Il corpo della richiesta non è un manifest valido. Invia manifest.json byte per byte.
TRANSFER_UNSUPPORTED_FORMAT422Aggiorna EmDash sulla destinazione.
TRANSFER_UNSUPPORTED_FEATURE422Aggiorna EmDash sulla destinazione.
TRANSFER_CONTAINER_INVALID422Il file .emdash non è un archivio di pacchetto valido. Scaricalo di nuovo.
TRANSFER_PLAN_BLOCKED409Il piano contiene blocchi. Consulta esaminare il piano di importazione.
TRANSFER_PACKAGE_DIGEST_MISMATCH409Il digest non corrisponde al pacchetto caricato. Usa il packageDigest dell’operazione.
TRANSFER_PLAN_DIGEST_MISMATCH409Il piano è cambiato da quando lo hai esaminato. Leggi il piano corrente ed esaminalo di nuovo.
TRANSFER_DECISIONS_INVALID422Una decisione indica un principal sconosciuto o un utente di destinazione inesistente. Correggi l’associazione.
TRANSFER_INVALID_STATE409L’operazione non si trova in uno stato che consente la richiesta. Leggi l’operazione e segui il suo state.
TRANSFER_LEASE_ACTIVE409Un’altra richiesta sta eseguendo un passaggio. Attendi e riprova.
TRANSFER_IDEMPOTENCY_CONFLICT409La 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_MISMATCH409Una versione incompatibile di EmDash ha avviato l’operazione. Completala con la versione che l’ha avviata, oppure avviane una nuova.
TRANSFER_VERIFICATION_FAILED422Il sito importato non corrisponde al pacchetto. Leggi le differenze in errorDetail, abbandona l’importazione e importa in un nuovo sito.
TRANSFER_APPROVAL_REQUIRED403Un amministratore deve approvare la richiesta. Consulta approvazioni per gli agenti.
TRANSFER_APPROVAL_INVALID403L’approvazione è sconosciuta, rifiutata, scaduta, già usata o vincolata ad altri parametri. Richiedine una nuova.
TRANSFER_SCHEMA_UNCLASSIFIED500Il database contiene una tabella o una colonna che l’esportatore non riconosce. Esegui la versione di EmDash corrispondente alle migrazioni del database.
INSUFFICIENT_SCOPE403Il token non ha né admin né l’ambito di trasferimento necessario alla richiesta. Emetti un token con quell’ambito.