Fichiers seed

Sur cette page

Un fichier seed décrit le modèle initial et les données d’exemple optionnelles d’un site EmDash. Les modèles actuels le stockent dans seed/seed.json et y pointent avec package.json#emdash.seed.

EmDash intègre le seed au moment du build. Il est destiné à la première configuration et aux commandes seed explicites, pas comme une migration qui s’exécute à chaque déploiement.

Découverte du fichier

L’intégration Astro recherche un seed dans cet ordre :

  1. .emdash/seed.json.
  2. Le chemin indiqué dans package.json#emdash.seed.
  3. seed/seed.json.
  4. Le seed par défaut intégré lorsqu’aucun seed utilisateur n’existe.

Le champ de package suivant sélectionne le chemin conventionnel du modèle :

{
  "emdash": {
    "seed": "seed/seed.json"
  }
}

Forme racine

L’exemple suivant contient toutes les propriétés racines :

{
  "$schema": "https://emdashcms.com/seed.schema.json",
  "version": "1",
  "defaultLocale": "en",
  "meta": {
    "name": "Publication",
    "description": "A publication seed",
    "author": "Example Studio"
  },
  "settings": {},
  "blockTypes": [],
  "collections": [],
  "relations": [],
  "taxonomies": [],
  "bylines": [],
  "content": {},
  "menus": [],
  "redirects": [],
  "widgetAreas": [],
  "sections": []
}
PropriétéObligatoireRôle
$schemaNonURL du schéma pour l’éditeur
versionOuiFormat du seed ; la seule valeur acceptée est "1"
defaultLocaleNonLocale pour les lignes porteuses de locale qui omettent locale ; par défaut la configuration d’exécution, puis en
metaNonNom descriptif, description et auteur affichés pendant la configuration
settingsNonRéglages partiels du site
blockTypesNonDéfinitions versionnées utilisées par les champs blocks
collectionsNonDéfinitions de collections et de champs
taxonomiesNonDéfinitions de taxonomies et termes optionnels
bylinesNonProfils optionnels de crédits de présentation
contentNonEntrées d’exemple regroupées par slug de collection
menusNonMenus et éléments imbriqués
redirectsNonRègles de redirection locales
widgetAreasNonZones de widgets et widgets
sectionsNonSections Portable Text réutilisables

defaultLocale doit être une chaîne non vide, sans espace au début ni à la fin.

Réglages

settings est un objet de réglages partiels du site. Les propriétés courantes sont title, tagline, logo, favicon, url, postsPerPage, dateFormat, timezone, social et seo.

L’assistant de configuration permet à l’administrateur de remplacer le titre et le slogan semés. La valeur par défaut onConflict: "skip" conserve ces valeurs lorsque le seed est appliqué de nouveau et complète tous les réglages fournis qui manquent encore.

{
  "version": "1",
  "settings": {
    "title": "Field Notes",
    "tagline": "Reports from the team",
    "postsPerPage": 12,
    "dateFormat": "MMMM d, yyyy",
    "timezone": "Europe/London"
  }
}

Types de blocs

blockTypes définit les formes versionnées utilisées par les champs de collection blocks. EmDash applique ces définitions avant les collections, de sorte qu’un champ peut les nommer dans validation.allowedTypes.

Le seed suivant conserve la version 1 pour le contenu et les révisions stockés tout en rendant la version 2 active pour les nouveaux blocs :

{
  "version": "1",
  "blockTypes": [
    {
      "slug": "hero",
      "label": "Hero",
      "category": "Layout",
      "currentVersion": 2,
      "versions": [
        {
          "version": 1,
          "fields": [
            { "slug": "heading", "label": "Heading", "type": "string", "required": true }
          ]
        },
        {
          "version": 2,
          "fields": [
            { "slug": "title", "label": "Title", "type": "string", "required": true },
            { "slug": "image", "label": "Image", "type": "image" }
          ]
        }
      ]
    }
  ],
  "collections": [
    {
      "slug": "pages",
      "label": "Pages",
      "fields": [
        {
          "slug": "layout",
          "label": "Layout",
          "type": "blocks",
          "validation": { "allowedTypes": ["hero"], "maxItems": 20 }
        }
      ]
    }
  ]
}

Les numéros de version sont des entiers positifs contigus commençant à 1. currentVersion doit nommer une version déclarée. Exporter puis réappliquer un seed conserve les numéros de version exacts et le pointeur de version active ; EmDash ne les renumérote pas.

Avec onConflict: "update", un seed peut modifier une version stockée uniquement lorsque la nouvelle définition est compatible. Réutiliser un numéro existant pour une définition incompatible échoue avec BLOCK_TYPE_VERSION_CONFLICT. Ajoutez un nouveau numéro de version pour une définition qui rompt la compatibilité.

Les valeurs de bloc stockées incluent _type, _version et _key. Fournissez ces propriétés lorsque le contenu du seed cible une version conservée. L’exécution attribue la version active et une clé lorsqu’un bloc nouvellement écrit les omet.

Collections

Une collection requiert slug, label et fields :

{
  "version": "1",
  "collections": [
    {
      "slug": "posts",
      "label": "Posts",
      "labelSingular": "Post",
      "description": "Published articles",
      "supports": ["drafts", "revisions", "scheduling", "search", "seo"],
      "urlPattern": "/posts/{slug}",
      "routable": true,
      "commentsEnabled": true,
      "editLocking": true,
      "titleField": "title",
      "dateField": "event_date",
      "admin": {
        "listColumns": ["event_date"]
      },
      "fields": [
        { "slug": "title", "label": "Title", "type": "string", "required": true },
        { "slug": "event_date", "label": "Event date", "type": "datetime", "indexed": true },
        { "slug": "content", "label": "Content", "type": "portableText" }
      ]
    }
  ]
}

Propriétés de collection

PropriétéTypeComportement
slugstringNom obligatoire de base de données et d’API ; commence par une lettre minuscule et contient des lettres minuscules, des chiffres et des tirets bas
labelstringLibellé d’interface obligatoire au pluriel
labelSingularstringLibellé d’interface facultatif au singulier
descriptionstringDescription facultative dans l’administration
iconstringNom de l’icône Phosphor de l’entrée de la barre latérale, par exemple calendar-blank
admin.listColumnsstring[]Jusqu’à quatre slugs de champs déclarés affichés dans la liste de contenu
admin.quickCreatebooleanIndique si le tableau de bord affiche une action rapide « Nouvelle entrée » pour cette collection ; true par défaut
supportsstring[]Toute combinaison de drafts, revisions, preview, scheduling, search et seo
urlPatternstringMotif public tel que /posts/{slug}, avec au plus un espace réservé par segment de chemin
routablebooleanIndique si les entrées publiées requièrent un slug ; true par défaut
hiddenbooleanMasque le lien généré de la barre latérale, le lien de la palette de commandes et l’action rapide du tableau de bord ; la collection reste accessible par URL et par API
sortOrdernumberPosition explicite dans la barre latérale de l’administration ; les collections ordonnées viennent en premier, par ordre croissant
groupstringDossier de la barre latérale de l’administration ; les collections ayant le même groupe partagent une entrée repliable
commentsEnabledbooleanActive les commentaires pour la collection
editLockingbooleanActive les verrous d’édition ; true par défaut
titleFieldstringChamp utilisé pour le titre dans la liste de contenu
dateFieldstringChamp datetime utilisé pour la date dans la liste de contenu
fieldsSeedField[]Définitions de champs obligatoires

sortOrder appartient à la collection et contrôle l’ordre de la barre latérale. SeedField n’a pas de propriété sortOrder. Les champs sont créés dans l’ordre de leur tableau.

Propriétés de champ

PropriétéTypeRôle
slugstringNom de champ obligatoire suivant le motif du slug de collection
labelstringLibellé d’interface obligatoire
typeFieldTypeType de champ stocké obligatoire
requiredbooleanRejette une valeur obligatoire vide
uniquebooleanAjoute une contrainte d’unicité
searchablebooleanInclut le champ dans la recherche de la collection
indexedbooleanAjoute un index de requête pour les types scalaires pris en charge
translatablebooleanStocke une valeur par locale ; true par défaut. false partage une valeur unique entre les traductions
defaultValuen’importe lequelValeur initiale lorsque le champ est omis
validationobjetRègles de validation utilisées par les schémas de contenu générés
widgetstringRemplacement du widget du champ dans l’administration
optionsobjetOptions propres au widget

Les types de champ pris en charge sont :

  • string, text, url et slug.
  • number, integer et boolean.
  • datetime.
  • select et multiSelect.
  • portableText, json et repeater.
  • blocks.
  • image, file et reference.

Un champ reference ne stocke rien dans la table de la collection. Ses liens résident dans la relation à laquelle il est lié ; voir Relations.

Seuls string, url, number, integer, boolean, datetime, select, reference et slug peuvent définir indexed: true. Sur un champ reference, l’indicateur ne s’applique que tant que le champ n’a pas de relation, car un champ lié n’a pas de colonne à indexer.

Validation de champ

Le schéma de collection généré reconnaît ces règles là où le type de champ les prend en charge :

RègleUtilisée par
min, maxChamps numériques
minLength, maxLength, patternChamps de forme chaîne
optionsselect et multiSelect
subFields, minItems, maxItemsrepeater
allowedTypes, minItems, maxItemsblocks
allowedMimeTypesChamps média

retiredTypes sur un champ blocks est géré par le serveur. Retirer un slug de allowedTypes le met hors service : les blocs stockés existants restent valides, mais les nouveaux blocs ne peuvent pas l’utiliser.

validateSeed() ne vérifie pas en profondeur le type de chaque règle de validation ou options. Une règle invalide peut donc passer la validation du seed et échouer plus tard, lorsque le schéma de collection est construit ou que du contenu est écrit.

Relations

Une relation joint deux collections et possède les liens entre leurs entrées. Un champ reference se lie à l’une d’elles et voit ses liens depuis une extrémité. Le seed suivant déclare une relation entre posts et authors qui autorise un auteur par article :

{
	"relations": [
		{
			"slug": "post_authors",
			"parentCollection": "posts",
			"childCollection": "authors",
			"parentLabel": "Posts",
			"parentLabelSingular": "Post",
			"childLabel": "Authors",
			"childLabelSingular": "Author",
			"maxChildrenPerParent": 1
		}
	]
}
PropriétéTypeObligatoireDescription
slugstringOuiNom unique par lequel un champ reference l’adresse
parentCollectionstringOuiCollection à l’extrémité parente
childCollectionstringOuiCollection à l’extrémité enfant
parentLabelstringOuiNomme le rôle du parent, vu depuis l’enfant
parentLabelSingularstringNonForme singulière de parentLabel
childLabelstringOuiNomme le rôle de l’enfant, vu depuis le parent
childLabelSingularstringNonForme singulière de childLabel
maxChildrenPerParentnumber | nullNonNombre d’enfants qu’un parent peut lier (null : pas de limite)
maxParentsPerChildnumber | nullNonNombre de parents qu’un enfant peut lier (null : pas de limite)

Un champ reference dans collections nomme la relation à laquelle il se lie :

{
	"slug": "author",
	"label": "Author",
	"type": "reference",
	"validation": { "relation": "post_authors" }
}

Un champ peut à la place nommer une targetCollection et faire créer une relation pour lui, ce qui est le chemin le plus court pour un lien que seule une collection voit. Déclarez la relation dans relations lorsque les deux collections doivent la voir, ou pour définir ses libellés et ses limites. reference documente les deux formes et les clés de validation que chacune accepte.

Les deux collections d’une relation sont figées une fois qu’elle existe : un seed qui en nomme d’autres échoue, plutôt que de laisser les liens qu’elle contient pointer vers une collection qui n’en est plus une extrémité. Les libellés et les limites sont mis à jour lorsque le seed est appliqué avec onConflict: "update".

Taxonomies

Les définitions de taxonomie identifient leurs collections cibles. Les termes sont des données d’exemple et ne sont appliqués que lorsque includeContent est true.

{
  "version": "1",
  "taxonomies": [
    {
      "name": "category",
      "label": "Categories",
      "labelSingular": "Category",
      "hierarchical": true,
      "collections": ["posts"],
      "terms": [
        { "slug": "engineering", "label": "Engineering" },
        { "slug": "platform", "label": "Platform", "parent": "engineering" }
      ]
    }
  ]
}

Une taxonomie peut porter un id local au seed, locale et translationOf. Les termes peuvent aussi porter ces propriétés. translationOf fait référence à un autre ID local au seed. Un terme doit être ordonné après le terme qu’il traduit. Les entrées de taxonomie ayant le même name peuvent apparaître dans n’importe quel ordre, car l’entrée qui déclare la structure de la taxonomie est appliquée avant ses traductions.

hierarchical et collections sont partagés par toutes les locales d’une taxonomie, de sorte qu’une entrée de taxonomie dont translationOf pointe vers une entrée ayant le même name peut les omettre. Le moteur d’application suit translationOf à travers les entrées ayant le même name et les prend de la dernière. La validation avertit lorsqu’une traduction déclare des valeurs autres que celles qu’elle prend, ou lorsque deux entrées qui les déclarent pour une même taxonomie ne concordent pas. Une taxonomie existante conserve ses valeurs, sauf si une entrée sans translationOf les remplace. Cela se produit avec onConflict: "update", et dans tous les modes lorsque la locale de l’entrée possède la définition intégrée category ou tag non modifiée décrite dans Comportement de conflit, ou lorsque cette définition intégrée est la seule de la taxonomie. L’export ne les écrit que sur l’entrée vers laquelle pointent les traductions.

Le parent d’un terme est le slug du terme parent dans la même locale. Un parent sur une taxonomie non hiérarchique produit un avertissement et est ignoré. Un terme avec translationOf et sans parent prend le parent du terme qu’il traduit.

Bylines

Les bylines racines définissent des crédits de présentation. Ce sont des données d’exemple et elles requièrent includeContent: true.

{
  "version": "1",
  "bylines": [
    {
      "id": "byline-editor",
      "slug": "alex-editor",
      "displayName": "Alex Editor",
      "isGuest": true
    }
  ]
}

L’id est local au seed et est utilisé par les crédits du contenu. Les propriétés facultatives sont bio, websiteUrl, isGuest et avatar.

L’avatar d’un byline pointe vers un fichier qui existe déjà dans le stockage configuré :

{
  "id": "byline-editor",
  "slug": "alex-editor",
  "displayName": "Alex Editor",
  "avatar": {
    "storageKey": "avatars/alex.jpg",
    "filename": "alex.jpg",
    "mimeType": "image/jpeg",
    "alt": "Alex Editor",
    "width": 400,
    "height": 400
  }
}

Le semis de l’avatar d’un byline crée ou réutilise une ligne de média pour la clé de stockage. Il ne téléverse ni ne télécharge le fichier.

Contenu

content regroupe les entrées par slug de collection. Chaque entrée requiert un id local au seed et un objet data. Les collections routables requièrent aussi un slug non vide.

{
  "version": "1",
  "content": {
    "posts": [
      {
        "id": "post-welcome",
        "slug": "welcome",
        "status": "published",
        "data": {
          "title": "Welcome",
          "content": []
        },
        "taxonomies": {
          "category": ["engineering"]
        },
        "bylines": [
          { "byline": "byline-editor", "roleLabel": "Editor" }
        ]
      }
    ]
  }
}
PropriétéObligatoireComportement
idOuiID de référence local au seed
slugPour les collections routablesSlug public et clé de conflit
statusNonpublished ou draft ; published par défaut
dataOuiValeurs indexées par le slug de champ de la collection
taxonomiesNonNom de taxonomie vers tableau de slugs de termes
bylinesNonCrédits ordonnés faisant référence à des IDs de byline racines
localeNonLocale BCP 47 ; par défaut via defaultLocale
translationOfNonID de contenu local au seed dans la même collection

Pour une entrée routable, l’id local au seed n’est pas son identité en base de données. EmDash crée un ID de base de données et enregistre la correspondance pour les références ultérieures. Pour une entrée sans slug dans une collection avec routable: false, EmDash utilise l’id du seed comme ID stocké afin que la réapplication reste idempotente.

À la lecture, entry.id est l’identifiant de route Astro et correspond normalement au slug. L’ID stocké en base de données est entry.data.id.

Références de contenu

Utilisez une chaîne $ref: dans data pour remplacer un ID de contenu local au seed par l’ID de base de données créé :

{
  "id": "event-opening",
  "slug": "opening-night",
  "data": {
    "title": "Opening night",
    "venue": "$ref:venue-main-hall"
  }
}

Les cibles de référence doivent apparaître assez tôt pour être présentes dans la table d’IDs du moteur d’application. Une valeur $ref: non résolue reste telle quelle comme chaîne littérale d’origine ; validateSeed() ne la rejette pas.

Pour un champ reference, déclarez les liens depuis l’extrémité parente de sa relation. Les deux extrémités voient un même ensemble de liens ; un champ sur la collection enfant répéterait donc des liens que le parent porte déjà.

Références multimédias

Utilisez $media dans les données de contenu pour télécharger une URL, la téléverser avec l’adaptateur de stockage fourni, créer une ligne de média et remplacer l’objet par une valeur de champ média :

{
  "featured_image": {
    "$media": {
      "url": "https://example.com/images/launch.jpg",
      "filename": "launch.jpg",
      "alt": "A product launch on stage",
      "caption": "Launch event"
    }
  }
}

Dans un bloc Portable Text image ou une image de gallery, $media dans asset devient une référence de média (_type: "reference", _ref, url, provider), et le texte alternatif et les dimensions du média renseignent les propres alt, width et height de l’image lorsqu’ils manquent.

Au sein d’un même appel d’application, les références répétées à la même URL réutilisent la valeur de média déjà résolue. Les références de média du seed n’acceptent pas de propriété locale file. mediaBasePath reste dans le type public SeedApplyOptions, mais le moteur d’application actuel ne le lit pas.

Lorsqu’aucun adaptateur de stockage n’est fourni, les références $media sont ignorées et résolues en null. Avec skipMediaDownload: true, elles deviennent des valeurs de média externes et aucun adaptateur de stockage n’est requis.

Les menus sont des données structurelles et sont appliqués même lorsque includeContent est false :

{
  "version": "1",
  "menus": [
    {
      "name": "primary",
      "label": "Primary navigation",
      "items": [
        {
          "type": "page",
          "label": "About",
          "ref": "page-about",
          "collection": "pages"
        },
        {
          "type": "custom",
          "label": "Contact",
          "url": "/contact",
          "target": "_self"
        }
      ]
    }
  ]
}

Les types d’élément autorisés sont custom, page, post, taxonomy et collection. custom requiert url ; page et post requièrent ref. Les éléments peuvent inclure id, translationOf, label, collection, titleAttr, cssClasses, locale, target et des children imbriqués.

Pour page et post, ref nomme un ID de contenu du seed. Une cible manquante produit un avertissement de validation et un élément de menu sans référence de contenu résolue. Les éléments de menu existants sont supprimés puis recréés chaque fois que ce menu est appliqué, indépendamment de onConflict.

Redirections

Les redirections requièrent des chemins source et destination locaux :

{
  "version": "1",
  "redirects": [
    {
      "source": "/old-path",
      "destination": "/new-path",
      "type": 308,
      "enabled": true,
      "groupName": "WordPress migration"
    }
  ]
}

Les deux chemins doivent commencer par un seul /. Les URL relatives au protocole, les segments de traversée de chemin et les sauts de ligne sont rejetés. Les codes d’état autorisés sont 301, 302, 307 et 308.

Zones de widgets

Une zone de widgets contient des widgets content, menu ou component :

{
  "version": "1",
  "widgetAreas": [
    {
      "name": "sidebar",
      "label": "Sidebar",
      "widgets": [
        {
          "type": "menu",
          "title": "Explore",
          "menuName": "primary"
        },
        {
          "type": "component",
          "title": "Recent posts",
          "componentId": "core:recent-posts",
          "props": { "count": 5 }
        }
      ]
    }
  ]
}

Un widget content stocke du Portable Text dans content. Un widget menu requiert menuName. Un widget component requiert componentId et peut transmettre props. SeedWidget n’a pas de propriété settings.

Les widgets existants d’une zone sont supprimés puis recréés chaque fois que la zone est appliquée, indépendamment de onConflict.

Sections

Les sections contiennent du contenu Portable Text réutilisable :

{
  "version": "1",
  "sections": [
    {
      "slug": "newsletter-signup",
      "title": "Newsletter signup",
      "description": "Signup call to action",
      "keywords": ["newsletter", "email"],
      "source": "theme",
      "content": []
    }
  ]
}

Les slugs de section contiennent des lettres minuscules, des chiffres et des tirets. source vaut theme, user ou import ; un seed la définit par défaut sur theme. Les sections de thème ne peuvent pas être supprimées dans l’administration. Les sections sont structurelles et sont appliquées même lorsque includeContent est false.

Localisation

defaultLocale renseigne les locales manquantes pour les taxonomies, les termes, les menus, les éléments de menu et le contenu. La configuration i18n active à l’exécution prévaut lorsqu’elle est présente.

Les taxonomies, termes, menus, éléments de menu et contenus localisés utilisent les champs id et translationOf locaux au seed. Placez l’élément source avant une traduction afin que le moteur d’application puisse résoudre son groupe de traduction. Une entrée de contenu traduite doit définir locale, et son translationOf doit nommer une autre entrée de la même collection.

Appliquer un seed de façon programmatique

applySeed() et validateSeed() sont exportés depuis emdash/seed. L’assistant suivant valide avant d’appliquer :

import {
  applySeed,
  validateSeed,
  type SeedApplyOptions,
  type SeedFile,
} from "emdash/seed";

type SeedDatabase = Parameters<typeof applySeed>[0];

export async function applyProjectSeed(
  db: SeedDatabase,
  seed: SeedFile,
  options: SeedApplyOptions,
) {
  const validation = validateSeed(seed);
  if (!validation.valid) {
    throw new Error(validation.errors.join("\n"));
  }

  return applySeed(db, seed, options);
}

SeedApplyOptions

OptionValeur par défautComportement actuel
includeContentfalseInclut les entrées de contenu, les bylines et les termes de taxonomie
onConflict"skip""skip", "update" ou "error" pour les conflits d’entités pris en charge
storageaucunAdaptateur de stockage requis pour télécharger les URL $media
skipMediaDownloadfalseConserve les URL $media comme valeurs de média externes
mediaBasePathaucunPrésent dans le type public, mais non utilisé par le moteur d’application actuel

L’application programmatique définit includeContent sur false par défaut. L’assistant de configuration transmet le choix de l’administrateur concernant le contenu d’exemple. La CLI emdash seed inclut le contenu par défaut, sauf si --no-content est défini.

Comportement de conflit

onConflict n’est pas une politique de transaction pour tout le seed :

  • Collections, champs, bylines, contenu, redirections et sections prennent en charge les comportements skip, update et error.
  • Les définitions et termes de taxonomie respectent le mode de conflit applicable. L’exception concerne les définitions intégrées category et tag avec lesquelles commence chaque nouvelle base de données : tant qu’un site ne les a pas modifiées, un seed qui les déclare les remplace dans tous les modes.
  • Les réglages utilisent une gestion de conflit par clé. skip crée les réglages manquants et conserve les valeurs existantes. update écrase chaque réglage fourni ; pour seo et social, seuls les champs fournis sont écrasés. error s’arrête au premier réglage existant ; les réglages créés plus tôt dans l’ordre du seed restent appliqués.
  • Les menus existants conservent leur ligne de menu mais remplacent tous les éléments.
  • Les zones de widgets existantes conservent leur ligne de zone mais remplacent tous les widgets.
  • Un conflit de contenu est apparié par collection, slug et locale. Une entrée sans slug dans une collection non routable est appariée par son ID de seed.

Avec onConflict: "update", les données de contenu sont remplacées et leurs attributions de byline et de taxonomie sont réconciliées avec le seed. Testez le mode update sur une copie avant de l’utiliser contre un site existant.

applySeed() renvoie des compteurs pour les collections, champs, taxonomies, bylines, menus, redirections, zones de widgets, sections, réglages, contenu et médias.

Comportement de validation

validateSeed() renvoie { valid, errors, warnings }. applySeed() l’appelle et lance Invalid seed file lorsque des erreurs sont présentes.

Le validateur vérifie les règles structurelles requises par le moteur d’application, notamment :

  • Version et defaultLocale non vide.
  • Formes des conteneurs de collection, champ, taxonomie, terme, menu, zone de widgets, section, byline et contenu.
  • Noms, libellés, IDs, slugs requis et types de champ ou de widget pris en charge.
  • Identifiants en double dans leur portée pertinente.
  • Types de champ indexables et références admin.listColumns.
  • Parents de taxonomie, traductions de contenu, références de byline dans le contenu et exigences des éléments de menu.
  • Chemins de redirection locaux sûrs et codes d’état.

Certaines conditions sont des avertissements plutôt que des erreurs. Exemples : une taxonomie sans collections, un parent sur une taxonomie plate, ou une référence de contenu de menu absente du seed.

Le validateur ne prouve pas que toutes les valeurs data correspondent à leurs champs de collection. Il ne valide pas non plus en profondeur les réglages du site, la validation du champ, les options du champ, les blocs Portable Text arbitraires, les props de widgets component, les cibles $ref: dans les données de contenu, ni la disponibilité distante de $media. Un seed valide peut encore échouer pendant la création du schéma, la validation de contenu, le téléchargement réseau ou le téléversement vers le stockage.

Utilisez l’URL $schema pour l’assistance de l’éditeur et exécutez le validateur exécutable avant d’appliquer :

npx emdash seed seed/seed.json --validate

Commandes CLI

Appliquez un seed à une base de données SQLite locale avec un comportement de conflit explicite :

npx emdash seed seed/seed.json --database ./data.db --on-conflict skip

Exportez le modèle local actuel et tout le contenu vers le chemin du modèle :

npx emdash export-seed --database ./data.db --with-content=all > seed/seed.json

export-seed fonctionne directement sur un fichier SQLite local. Pour une base de données D1 déployée, exportez-la d’abord vers un fichier local. Examinez les réglages, le contenu et les références de média exportés avant de valider le résultat. Pour rendre les médias exportés importables sur un autre site, passez --media-base-url ; voir URL des médias.

Étapes suivantes