Arquivos seed

Nesta página

Um arquivo seed descreve o esquema inicial e dados de exemplo opcionais para um site EmDash. Os templates atuais o armazenam em seed/seed.json e o apontam com package.json#emdash.seed.

O EmDash incorpora o seed no build. Destina-se à configuração inicial e a comandos seed explícitos, não a uma migração executada a cada implantação.

Descoberta do arquivo

A integração Astro procura um seed nesta ordem:

  1. .emdash/seed.json.
  2. O caminho em package.json#emdash.seed.
  3. seed/seed.json.
  4. O seed padrão embutido quando não existe um seed do usuário.

O seguinte campo do pacote seleciona o caminho convencional do template:

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

Forma raiz

O exemplo a seguir contém todas as propriedades raiz:

{
  "$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": []
}
PropertyRequiredPurpose
$schemaNoURL do schema do editor
versionYesFormato seed; o único valor aceito é "1"
defaultLocaleNoLocale para linhas com locale que omitem locale; padrão a configuração em runtime, depois en
metaNoNome descritivo, descrição e autor mostrados durante a configuração
settingsNoConfigurações parciais do site
blockTypesNoDefinições versionadas usadas por campos blocks
collectionsNoDefinições de collection e campo
taxonomiesNoDefinições de taxonomia e termos opcionais
bylinesNoPerfis opcionais de créditos de apresentação
contentNoEntradas de exemplo agrupadas por slug de collection
menusNoMenus e itens aninhados
redirectsNoRegras de redirect locais
widgetAreasNoÁreas de widget e widgets
sectionsNoSections Portable Text reutilizáveis

defaultLocale deve ser uma string não vazia sem espaços no início ou no fim.

Settings

settings é um objeto parcial de configurações do site. Propriedades comuns são title, tagline, logo, favicon, url, postsPerPage, dateFormat, timezone, social e seo.

O assistente de configuração permite que o administrador substitua o título e o tagline seedados. O padrão onConflict: "skip" preserva esses valores quando o seed é reaplicado e preenche quaisquer configurações fornecidas ainda ausentes.

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

Tipos de bloco

blockTypes define as formas versionadas usadas pelos campos blocks das collections. O EmDash aplica essas definições antes das collections, para que um campo possa nomeá-las em validation.allowedTypes.

O seed a seguir mantém a versão 1 para conteúdo e revisões armazenados enquanto torna a versão 2 ativa para novos blocos:

{
  "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 }
        }
      ]
    }
  ]
}

Os números de versão são inteiros positivos contíguos a partir de 1. currentVersion deve nomear uma versão declarada. Exportar e reaplicar um seed preserva os números de versão exatos e o ponteiro ativo; o EmDash não os renumera.

Com onConflict: "update", um seed só pode alterar uma versão armazenada quando a nova definição é compatível. Reutilizar um número existente para uma definição incompatível falha com BLOCK_TYPE_VERSION_CONFLICT. Adicione um novo número de versão para uma definição incompatível.

Os valores de bloco armazenados incluem _type, _version e _key. Forneça essas propriedades quando o conteúdo do seed apontar para uma versão retida. O runtime atribui a versão ativa e uma chave quando um bloco recém-escrito as omite.

Collections

Uma collection exige slug, label e 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" }
      ]
    }
  ]
}

Propriedades da collection

PropertyTypeBehavior
slugstringNome obrigatório de banco de dados e API; começa com letra minúscula e contém letras minúsculas, dígitos e underscores
labelstringRótulo de UI plural obrigatório
labelSingularstringRótulo de UI singular opcional
descriptionstringDescrição de administração opcional
iconstringNome de ícone opcional
admin.listColumnsstring[]Até quatro slugs de campo declarados mostrados na lista de conteúdo
supportsstring[]Qualquer um de drafts, revisions, preview, scheduling, search e seo
urlPatternstringPadrão público como /posts/{slug}
routablebooleanSe entradas publicadas exigem um slug; padrão true
hiddenbooleanOculta o link gerado da barra lateral e a ação rápida do painel; a collection permanece alcançável por URL e API
sortOrdernumberPosição explícita na barra lateral de administração; collections ordenadas vêm primeiro, em ordem crescente
groupstringPasta da barra lateral de administração; collections com o mesmo grupo compartilham uma entrada recolhível
commentsEnabledbooleanAtiva comentários para a collection
editLockingbooleanAtiva bloqueios de edição; padrão true
titleFieldstringCampo usado para o título da lista de conteúdo
dateFieldstringCampo datetime usado para a data da lista de conteúdo
fieldsSeedField[]Definições de campo obrigatórias

sortOrder pertence à collection e controla a ordem da barra lateral. SeedField não tem propriedade sortOrder. Os campos são criados na ordem do array.

Propriedades do campo

PropertyTypePurpose
slugstringNome de campo obrigatório com o padrão de slug da collection
labelstringRótulo de UI obrigatório
typeFieldTypeTipo de campo armazenado obrigatório
requiredbooleanRejeita um valor obrigatório vazio
uniquebooleanAdiciona uma restrição de exclusividade
searchablebooleanInclui o campo na busca da collection
indexedbooleanAdiciona um índice de consulta para tipos escalares suportados
translatablebooleanArmazena um valor por locale; padrão true. false compartilha um valor entre traduções
defaultValueanyValor inicial quando o campo é omitido
validationobjectRegras de validação usadas pelos schemas de conteúdo gerados
widgetstringSubstituição do widget de campo de administração
optionsobjectOpções específicas do widget

Os tipos de campo suportados são:

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

Um campo reference não armazena nada na tabela da collection. Seus links vivem na relação à qual está ligado; veja Relations.

Somente string, url, number, integer, boolean, datetime, select, reference e slug podem definir indexed: true. Em um campo reference, o flag só se aplica enquanto o campo não tem relação, porque um campo ligado não tem coluna para indexar.

Validação do campo

O schema de collection gerado reconhece estas regras onde o tipo de campo as suporta:

RuleUsed by
min, maxCampos numéricos
minLength, maxLength, patternCampos em forma de string
optionsselect e multiSelect
subFields, minItems, maxItemsrepeater
allowedTypes, minItems, maxItemsblocks
allowedMimeTypesCampos de mídia

retiredTypes em um campo blocks é tratado no servidor. Remover um slug de allowedTypes o aposenta para que blocos armazenados existentes permaneçam válidos enquanto novos blocos não possam usá-lo.

validateSeed() não inspeciona profundamente cada regra em validation ou options. Uma regra inválida pode então passar na validação do seed e falhar depois quando o schema da collection for criado ou o conteúdo for escrito.

Relations

Uma relação une duas collections e possui os links entre suas entradas. Um campo reference se liga a uma e vê seus links de uma extremidade. O seed a seguir declara uma relação entre posts e authors que permite um autor por post:

{
	"relations": [
		{
			"slug": "post_authors",
			"parentCollection": "posts",
			"childCollection": "authors",
			"parentLabel": "Posts",
			"parentLabelSingular": "Post",
			"childLabel": "Authors",
			"childLabelSingular": "Author",
			"maxChildrenPerParent": 1
		}
	]
}
PropertyTypeRequiredDescription
slugstringYesNome exclusivo pelo qual um campo reference a endereça
parentCollectionstringYesCollection na extremidade pai
childCollectionstringYesCollection na extremidade filho
parentLabelstringYesNomeia o papel do pai, visto pelo filho
parentLabelSingularstringNoForma singular de parentLabel
childLabelstringYesNomeia o papel do filho, visto pelo pai
childLabelSingularstringNoForma singular de childLabel
maxChildrenPerParentnumber | nullNoQuantos filhos um pai pode vincular (null: sem limite)
maxParentsPerChildnumber | nullNoQuantos pais um filho pode vincular (null: sem limite)

Um campo reference em collections nomeia a relação à qual se liga:

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

Um campo pode em vez disso nomear um targetCollection e fazer com que uma relação seja criada para ele, que é o caminho mais curto para um link que só uma collection vê. Declare a relação em relations quando ambas as collections precisam vê-la, ou para definir seus rótulos e limites. reference documenta ambas as formas e as chaves de validação que cada uma aceita.

As duas collections de uma relação são fixas uma vez que ela existe: um seed que nomeia diferentes falha em vez de deixar que os links que ela detém apontem para uma collection que não é mais uma extremidade. Rótulos e limites são atualizados quando o seed é aplicado com onConflict: "update".

Taxonomias

As definições de taxonomia identificam suas collections de destino. Os termos são dados de exemplo e só são aplicados quando includeContent é 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" }
      ]
    }
  ]
}

Uma taxonomia pode carregar um id local ao seed, locale e translationOf. Os termos também podem carregar essas propriedades. translationOf refere-se a outro ID local ao seed. Um termo deve ser ordenado depois do termo que traduz. Entradas de taxonomia de um name podem aparecer em qualquer ordem, porque a entrada que declara a forma da taxonomia é aplicada antes de suas traduções.

hierarchical e collections são compartilhados por cada locale de uma taxonomia, então uma entrada de taxonomia cujo translationOf aponta para uma entrada com o mesmo name pode omiti-los. O motor de apply segue translationOf pelas entradas com o mesmo name e os toma da última. A validação avisa quando uma tradução declara valores diferentes dos que toma, ou quando duas entradas que os declaram para uma taxonomia não concordam. Uma taxonomia existente conserva seus valores a menos que uma entrada sem translationOf os substitua. Isso acontece com onConflict: "update", e em qualquer modo quando o locale da entrada tem a definição embutida intacta category ou tag descrita em Conflict behavior, ou quando essa definição embutida é a única da taxonomia. A exportação as escreve apenas na entrada para a qual as traduções apontam.

O parent do termo é o slug do termo pai no mesmo locale. Um pai em uma taxonomia não hierárquica produz um aviso e é ignorado. Um termo com translationOf e sem parent toma o pai do termo que traduz.

Bylines

Os bylines raiz definem créditos de apresentação. São dados de exemplo e exigem includeContent: true.

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

O id é local ao seed e é usado pelos créditos de conteúdo. Propriedades opcionais são bio, websiteUrl, isGuest e avatar.

Um avatar de byline aponta para um arquivo que já existe no storage configurado:

{
  "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
  }
}

O seeding do avatar de byline cria ou reutiliza uma linha de mídia para a chave de storage. Não faz upload nem download do arquivo.

Content

content agrupa entradas por slug de collection. Cada entrada exige um id local ao seed e um objeto data. Collections roteáveis também exigem um slug não vazio.

{
  "version": "1",
  "content": {
    "posts": [
      {
        "id": "post-welcome",
        "slug": "welcome",
        "status": "published",
        "data": {
          "title": "Welcome",
          "content": []
        },
        "taxonomies": {
          "category": ["engineering"]
        },
        "bylines": [
          { "byline": "byline-editor", "roleLabel": "Editor" }
        ]
      }
    ]
  }
}
PropertyRequiredBehavior
idYesID de referência local ao seed
slugPara collections roteáveisSlug público e chave de conflito
statusNopublished ou draft; padrão published
dataYesValores indexados por slug de campo da collection
taxonomiesNoNome da taxonomia para array de slugs de termo
bylinesNoCréditos ordenados que referenciam IDs de byline raiz
localeNoLocale BCP 47; padrão via defaultLocale
translationOfNoID de conteúdo local ao seed na mesma collection

Para uma entrada roteável, o id local ao seed não é sua identidade de banco de dados. O EmDash cria um ID de banco de dados e registra o mapeamento para referências posteriores. Para uma entrada sem slug em uma collection com routable: false, o EmDash usa o id do seed como ID armazenado para que a reaplicação permaneça idempotente.

Na leitura, entry.id é o identificador de rota Astro e normalmente é o slug. O ID de banco de dados armazenado é entry.data.id.

Referências de conteúdo

Use uma string $ref: dentro de data para substituir um ID de conteúdo local ao seed pelo ID de banco de dados criado:

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

Os destinos de referência devem aparecer cedo o bastante para estar no mapa de IDs do motor de apply. Um valor $ref: não resolvido permanece como a string literal original; validateSeed() não o rejeita.

Para um campo reference, declare os links a partir da extremidade pai de sua relação. Ambas as extremidades veem o mesmo conjunto de links, então um campo na collection filha reafirmaria links que o pai já carrega.

Referências de mídia

Use $media nos dados de conteúdo para baixar uma URL, fazer upload com o adaptador de storage fornecido, criar uma linha de mídia e substituir o objeto por um valor de campo de mídia:

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

Em um bloco Portable Text image ou uma imagem de gallery, $media em asset torna-se uma referência de mídia (_type: "reference", _ref, url, provider), e o texto alternativo e as dimensões da mídia preenchem alt, width e height da imagem quando ausentes.

Dentro de uma chamada de apply, referências repetidas à mesma URL reutilizam o valor de mídia resolvido. Referências de mídia do seed não aceitam uma propriedade file local. mediaBasePath permanece no tipo público SeedApplyOptions, mas o motor de apply atual não o lê.

Quando nenhum adaptador de storage é fornecido, as referências $media são ignoradas e resolvem para null. Com skipMediaDownload: true, tornam-se valores de mídia externos e um adaptador de storage não é necessário.

Os menus são dados estruturais e são aplicados mesmo quando includeContent é 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"
        }
      ]
    }
  ]
}

Os tipos de item permitidos são custom, page, post, taxonomy e collection. custom exige url; page e post exigem ref. Os itens podem incluir id, translationOf, label, collection, titleAttr, cssClasses, locale, target e children aninhados.

Para page e post, ref nomeia um ID de conteúdo do seed. Um destino ausente produz um aviso de validação e um item de menu sem uma referência de conteúdo resolvida. Itens de menu existentes são excluídos e recriados toda vez que aquele menu é aplicado, independentemente de onConflict.

Redirects

Os redirects exigem caminhos de origem e destino locais:

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

Ambos os caminhos devem começar com /. URLs relativas a protocolo, segmentos de path traversal e novas linhas são rejeitados. Os códigos de status permitidos são 301, 302, 307 e 308.

Áreas de widget

Uma área de widget contém 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 }
        }
      ]
    }
  ]
}

Um widget de conteúdo armazena Portable Text em content. Um widget de menu exige menuName. Um widget de componente exige componentId e pode passar props. Não há propriedade settings em SeedWidget.

Widgets existentes em uma área são excluídos e recriados toda vez que a área é aplicada, independentemente de onConflict.

Sections

As sections contêm conteúdo Portable Text reutilizável:

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

Os slugs de section contêm letras minúsculas, dígitos e hífens. source é theme, user ou import; um seed o define como theme por padrão. Sections de tema não podem ser excluídas na administração. As sections são estruturais e são aplicadas mesmo quando includeContent é false.

Localização

defaultLocale preenche locales ausentes para taxonomias, termos, menus, itens de menu e conteúdo. A configuração i18n ativa em runtime tem precedência quando presente.

Taxonomias, termos, menus, itens de menu e conteúdo localizados usam os campos id e translationOf locais ao seed. Coloque o item de origem antes de uma tradução para que o motor de apply possa resolver seu grupo de tradução. Uma entrada de conteúdo traduzida deve definir locale e seu translationOf deve nomear outra entrada na mesma collection.

Aplicar um seed programaticamente

applySeed() e validateSeed() são exportados de emdash/seed. O helper a seguir valida antes de aplicar:

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

OptionDefaultCurrent behavior
includeContentfalseInclui entradas de conteúdo, bylines e termos de taxonomia
onConflict"skip""skip", "update" ou "error" para conflitos de entidade suportados
storagenoneAdaptador de storage necessário para baixar URLs $media
skipMediaDownloadfalseMantém URLs $media como valores de mídia externos
mediaBasePathnonePresente no tipo público mas não usado pelo motor de apply atual

A aplicação programática define includeContent como false por padrão. O assistente de configuração passa a escolha de conteúdo de exemplo do administrador. A CLI emdash seed inclui conteúdo por padrão a menos que --no-content esteja definido.

Comportamento de conflito

onConflict não é uma política de transação para o seed inteiro:

  • Collections, campos, bylines, conteúdo, redirects e sections suportam os comportamentos skip, update e error.
  • Definições e termos de taxonomia respeitam o modo de conflito aplicável. A exceção são as definições embutidas category e tag com as quais todo banco novo começa: até que um site as altere, um seed que as declare as substitui em qualquer modo.
  • Settings usam tratamento de conflito por chave. skip cria configurações ausentes e preserva valores existentes. update sobrescreve cada configuração fornecida. error para na primeira configuração existente; configurações criadas antes na ordem do seed permanecem aplicadas.
  • Menus existentes conservam sua linha de menu mas substituem todos os itens.
  • Áreas de widget existentes conservam sua linha de área mas substituem todos os widgets.
  • Um conflito de conteúdo é correspondente por collection, slug e locale. Uma entrada sem slug em uma collection não roteável é correspondente pelo seu ID de seed.

Com onConflict: "update", os dados de conteúdo são substituídos e suas atribuições de byline e taxonomia são reconciliadas com o seed. Teste o modo update em uma cópia antes de usá-lo contra um site existente.

applySeed() retorna contadores para collections, campos, taxonomias, bylines, menus, redirects, áreas de widget, sections, settings, conteúdo e mídia.

Comportamento de validação

validateSeed() retorna { valid, errors, warnings }. applySeed() o chama e lança Invalid seed file quando há erros.

O validador verifica as regras estruturais exigidas pelo motor de apply, incluindo:

  • Versão e defaultLocale não vazio.
  • Formas de containers de collection, campo, taxonomia, termo, menu, área de widget, section, byline e conteúdo.
  • Nomes, rótulos, IDs, slugs obrigatórios e tipos de campo ou widget suportados.
  • Identificadores duplicados em seu escopo pertinente.
  • Tipos de campo indexados e referências admin.listColumns.
  • Pais de taxonomia, traduções de conteúdo, referências de byline de conteúdo e requisitos de itens de menu.
  • Caminhos de redirect locais seguros e códigos de status.

Algumas condições são avisos em vez de erros. Exemplos: uma taxonomia sem collections, um pai em uma taxonomia plana ou uma referência de conteúdo de menu ausente do seed.

O validador não prova que todos os valores data estão em conformidade com seus campos de collection. Também não valida profundamente configurações do site, validation do campo, options do campo, blocos Portable Text arbitrários, props de widget de componente, destinos $ref: nos dados de conteúdo ou a disponibilidade remota de $media. Um seed válido ainda pode falhar durante a criação do schema, validação de conteúdo, download de rede ou upload de storage.

Use a URL $schema para assistência do editor e execute o validador executável antes de aplicar:

npx emdash seed seed/seed.json --validate

Comandos CLI

Aplique um seed a um banco SQLite local com comportamento de conflito explícito:

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

Exporte o esquema local atual e todo o conteúdo de volta para o caminho do template:

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

export-seed trabalha diretamente em um arquivo SQLite local. Para um banco D1 implantado, exporte-o primeiro para um arquivo local. Revise configurações, conteúdo e referências de mídia exportados antes de fazer commit do resultado. Para tornar a mídia exportada importável em outro site, passe --media-base-url; veja Media URLs.

Próximos passos