Opções de armazenamento

Nesta página

O EmDash armazena mídia enviada (imagens, documentos, vídeos) em um backend de armazenamento configurável. Escolha com base na sua plataforma de deploy e requisitos.

Visão geral

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

Cloudflare R2 (Binding)

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

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 em wrangler.jsonc
publicUrlstringURL pública do bucket (opcional)

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. Painel do Cloudflare > R2 > seu bucket
  2. Habilitar acesso público em Configurações
  3. Adicionar 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.

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ãoURL CDN ou pública (opcional)

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

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

Qualquer campo omitido em s3({...}) é lido da variável de ambiente S3_* correspondente quando o processo inicia. Isso permite construir uma imagem de contêiner uma vez e injetar credenciais na inicialização sem reconstruir. Valores explícitos em s3({...}) sempre têm prioridade 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.

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

export default defineConfig({
	integrations: [
		emdash({
			// s3() with no args: all fields from S3_* environment variables
			storage: s3(),

			// Or mix: override one field, rest from environment
			// 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

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 de armazenamento
baseUrlstringURL base para servir arquivos

O baseUrl deve corresponder ao endpoint de arquivos de mídia do EmDash (/_emdash/api/media/file) a menos que você configure um servidor de arquivos estáticos 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 clientes façam upload diretamente para o armazenamento sem passar pelo seu servidor. Isso melhora o desempenho para arquivos grandes.

Uploads assinados são automáticos ao usar o adaptador S3. A interface de administração os utiliza 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 em vez disso)
  • Local

Interface de armazenamento

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;
}

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