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
| Armazenamento | Melhor Para | Recursos |
|---|---|---|
| R2 Binding | Cloudflare Workers | Zero configuração, rápido |
| S3 | Qualquer plataforma | Uploads assinados, suporte CDN |
| Local | Desenvolvimento | Armazenamento 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ção | Tipo | Descrição |
|---|---|---|
binding | string | Nome do binding R2 de wrangler.jsonc |
publicUrl | string | URL 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:
- Vá para o Painel do Cloudflare > R2 > seu bucket
- Habilite o acesso público em Configurações
- 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ção | Tipo | Obrigatório | Descrição |
|---|---|---|---|
endpoint | string | sim | URL do endpoint S3 |
bucket | string | sim | Nome do bucket |
accessKeyId | string | não* | Chave de acesso |
secretAccessKey | string | não* | Chave secreta |
region | string | não | Região (padrão: "auto") |
publicUrl | string | não | CDN 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 ambiente | Campo | Notas |
|---|---|---|
S3_ENDPOINT | endpoint | Deve ser uma URL http/https válida |
S3_BUCKET | bucket | |
S3_ACCESS_KEY_ID | accessKeyId | |
S3_SECRET_ACCESS_KEY | secretAccessKey | |
S3_REGION | region | Padrão: "auto" |
S3_PUBLIC_URL | publicUrl | Prefixo 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ção | Tipo | Descrição |
|---|---|---|
directory | string | Caminho do diretório para armazenamento de arquivos |
baseUrl | string | URL 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.