Opções de Armazenamento

Nesta página

O EmDash armazena mídias enviadas (imagens, documentos, vídeos) em um backend de armazenamento configurável. Escolha com base na sua plataforma de implantação e requisitos.

Visão Geral

ArmazenamentoMelhor ParaRecursos
R2 BindingCloudflare WorkersZero configuração, rápido
S3Qualquer plataformaUploads assinados, suporte CDN
LocalDesenvolvimentoArmazenamento simples de arquivos

Cloudflare R2 (Binding)

Use bindings R2 ao implantar no Cloudflare Workers para a integração mais rápida.

import emdash from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			storage: r2({ binding: "MEDIA" }),
		}),
	],
});

Configuração

OpçãoTipoDescrição
bindingstringNome do binding R2 de wrangler.jsonc
publicUrlstringURL público opcional para o bucket

Configuração Inicial

Adicione o binding R2 à sua configuração do Wrangler:

wrangler.jsonc

{
  "r2_buckets": [
    {
      "binding": "MEDIA",
      "bucket_name": "emdash-media"
    }
  ]
}

wrangler.toml

[[r2_buckets]]
binding = "MEDIA"
bucket_name = "emdash-media"

Acesso Público

Para URLs de mídia públicas, habilite o acesso público no seu bucket R2:

  1. Vá para o Painel do Cloudflare > R2 > seu bucket
  2. Habilite o acesso público em Configurações
  3. Adicione a URL pública à sua configuração:
storage: r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev",
});

Armazenamento Compatível com S3

O adaptador S3 funciona com Cloudflare R2 (via API S3), MinIO e outros serviços compatíveis com S3.

A seguinte configuração aponta o EmDash para um bucket compatível com S3:

import emdash, { s3 } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			storage: s3({
				endpoint: process.env.S3_ENDPOINT,
				bucket: process.env.S3_BUCKET,
				accessKeyId: process.env.S3_ACCESS_KEY_ID,
				secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
				region: "auto", // Optional, defaults to "auto"
				publicUrl: process.env.S3_PUBLIC_URL, // Optional CDN URL
			}),
		}),
	],
});

Configuração

OpçãoTipoObrigatórioDescrição
endpointstringsimURL do endpoint S3
bucketstringsimNome do bucket
accessKeyIdstringnão*Chave de acesso
secretAccessKeystringnão*Chave secreta
regionstringnãoRegião (padrão: "auto")
publicUrlstringnãoCDN opcional ou URL público

* Tanto accessKeyId quanto secretAccessKey devem ser fornecidos juntos, ou ambos omitidos.

Resolução de configuração S3 a partir de variáveis de ambiente

Qualquer campo omitido de s3({...}) é lido da variável de ambiente S3_* correspondente quando o processo inicia. Isso permite que você construa uma imagem de contêiner uma vez e injete credenciais na inicialização sem reconstrução. Valores explícitos em s3({...}) sempre têm precedência sobre variáveis de ambiente.

Variável de ambienteCampoNotas
S3_ENDPOINTendpointDeve ser uma URL http/https válida
S3_BUCKETbucket
S3_ACCESS_KEY_IDaccessKeyId
S3_SECRET_ACCESS_KEYsecretAccessKey
S3_REGIONregionPadrão: "auto"
S3_PUBLIC_URLpublicUrlPrefixo CDN opcional

As variáveis de ambiente são lidas de process.env quando o processo inicia. Este é um recurso exclusivo do Node.

Chamar s3() sem argumentos lê cada campo das variáveis de ambiente S3_*:

import emdash, { s3 } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			// s3() sem argumentos: todos os campos das variáveis de ambiente S3_*
			storage: s3(),

			// Ou misto: substituir um campo, o resto do ambiente
			// storage: s3({ publicUrl: "https://cdn.example.com" }),
		}),
	],
});

R2 via API S3

Use credenciais S3 com R2 para recursos como URLs de upload assinadas:

storage: s3({
	endpoint: "https://<account-id>.r2.cloudflarestorage.com",
	bucket: "emdash-media",
	accessKeyId: process.env.R2_ACCESS_KEY_ID,
	secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
	publicUrl: "https://pub-xxxx.r2.dev",
});

Gere credenciais de API R2 no painel do Cloudflare em R2 > Manage R2 API Tokens.

MinIO

Aponte o adaptador S3 para um endpoint MinIO com suas credenciais de acesso:

storage: s3({
	endpoint: "https://minio.example.com",
	bucket: "emdash-media",
	accessKeyId: process.env.MINIO_ACCESS_KEY,
	secretAccessKey: process.env.MINIO_SECRET_KEY,
	publicUrl: "https://minio.example.com/emdash-media",
});

Sistema de Arquivos Local

Use armazenamento local para desenvolvimento. Os arquivos são armazenados em um diretório no disco.

import emdash, { local } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			storage: local({
				directory: "./uploads",
				baseUrl: "/_emdash/api/media/file",
			}),
		}),
	],
});

Configuração

OpçãoTipoDescrição
directorystringCaminho do diretório para armazenamento de arquivos
baseUrlstringURL base para servir arquivos

A baseUrl deve corresponder ao endpoint de arquivo de mídia do EmDash (/_emdash/api/media/file), a menos que você configure um servidor de arquivo estático personalizado.

Configuração Baseada em Ambiente

Alterne backends de armazenamento com base no ambiente:

import emdash, { s3, local } from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";

const storage = import.meta.env.PROD
	? r2({ binding: "MEDIA" })
	: local({
			directory: "./uploads",
			baseUrl: "/_emdash/api/media/file",
		});

export default defineConfig({
	integrations: [emdash({ storage })],
});

Uploads Assinados

O adaptador S3 suporta URLs de upload assinadas, permitindo que os clientes façam upload diretamente para o armazenamento sem passar pelo seu servidor. Isso melhora o desempenho para arquivos grandes.

Os uploads assinados são automáticos ao usar o adaptador S3. A interface de administração os usa quando disponíveis.

Adaptadores que suportam uploads assinados:

  • S3 (incluindo R2 via API S3)

Adaptadores que não suportam uploads assinados:

  • R2 binding (use o adaptador S3 com credenciais R2)
  • Local

Interface Storage

Todos os adaptadores de armazenamento implementam a mesma interface:

interface Storage {
	upload(options: {
		key: string;
		body: Buffer | Uint8Array | ReadableStream;
		contentType: string;
	}): Promise<UploadResult>;

	download(key: string): Promise<DownloadResult>;
	delete(key: string): Promise<void>;
	exists(key: string): Promise<boolean>;
	list(options?: ListOptions): Promise<ListResult>;
	getSignedUploadUrl(options: SignedUploadOptions): Promise<SignedUploadUrl>;
	getPublicUrl(key: string): string;
}

Esta consistência permite alternar backends de armazenamento sem alterar o código da aplicação.