EmDash almacena los medios subidos (imágenes, documentos, videos) en un backend de almacenamiento configurable. Elija según su plataforma de despliegue y requisitos.
Resumen
| Almacenamiento | Ideal para | Características |
|---|---|---|
| R2 Binding | Cloudflare Workers | Sin configuración, rápido |
| S3 | Cualquier plataforma | Subidas firmadas, soporte CDN |
| Local | Desarrollo | Almacenamiento de archivos simple |
Cloudflare R2 (Binding)
Use bindings de R2 para la integración más rápida al desplegar en Cloudflare Workers.
import emdash from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
storage: r2({ binding: "MEDIA" }),
}),
],
});
Configuración
| Opción | Tipo | Descripción |
|---|---|---|
binding | string | Nombre del binding R2 en wrangler.jsonc |
publicUrl | string | URL pública del bucket (opcional) |
Configuración inicial
Añada el binding R2 a su configuración de Wrangler:
wrangler.jsonc
{
"r2_buckets": [
{
"binding": "MEDIA",
"bucket_name": "emdash-media"
}
]
} wrangler.toml
[[r2_buckets]]
binding = "MEDIA"
bucket_name = "emdash-media" Acceso público
Para URLs de medios públicas, habilite el acceso público en su bucket R2:
- Panel de Cloudflare > R2 > su bucket
- Habilitar acceso público en Configuración
- Añadir la URL pública a su configuración:
storage: r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev",
});
Almacenamiento compatible con S3
El adaptador S3 funciona con Cloudflare R2 (vía API S3), MinIO y otros servicios compatibles con 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
}),
}),
],
});
Configuración
| Opción | Tipo | Requerido | Descripción |
|---|---|---|---|
endpoint | string | sí | URL del endpoint S3 |
bucket | string | sí | Nombre del bucket |
accessKeyId | string | no* | Clave de acceso |
secretAccessKey | string | no* | Clave secreta |
region | string | no | Región (por defecto: "auto") |
publicUrl | string | no | URL CDN o pública (opcional) |
* accessKeyId y secretAccessKey deben proporcionarse juntos, o ambos omitirse.
Resolución de la configuración S3 desde variables de entorno
Cualquier campo omitido en s3({...}) se lee de la variable de entorno S3_*
correspondiente cuando el proceso se inicia. Esto le permite construir una imagen de
contenedor una vez e inyectar credenciales al arrancar sin reconstruir. Los valores
explícitos en s3({...}) siempre tienen prioridad sobre las variables de entorno.
| Variable de entorno | Campo | Notas |
|---|---|---|
S3_ENDPOINT | endpoint | Debe ser una URL http/https válida |
S3_BUCKET | bucket | |
S3_ACCESS_KEY_ID | accessKeyId | |
S3_SECRET_ACCESS_KEY | secretAccessKey | |
S3_REGION | region | Por defecto "auto" |
S3_PUBLIC_URL | publicUrl | Prefijo CDN opcional |
Las variables de entorno se leen de process.env cuando el proceso se inicia. Esta es una funcionalidad exclusiva de 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 vía API S3
Use credenciales S3 con R2 para funcionalidades como URLs de subida firmadas:
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",
});
Genere credenciales de API R2 en el panel de Cloudflare bajo 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 archivos local
Use almacenamiento local para desarrollo. Los archivos se almacenan en un directorio en disco.
import emdash, { local } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
}),
],
});
Configuración
| Opción | Tipo | Descripción |
|---|---|---|
directory | string | Ruta del directorio de almacenamiento |
baseUrl | string | URL base para servir archivos |
El baseUrl debe coincidir con el endpoint de archivos de medios de EmDash (/_emdash/api/media/file) a menos que configure un servidor de archivos estáticos personalizado.
Configuración según el entorno
Cambie backends de almacenamiento según el entorno:
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 })],
});
Subidas firmadas
El adaptador S3 admite URLs de subida firmadas, permitiendo a los clientes subir directamente al almacenamiento sin pasar por su servidor. Esto mejora el rendimiento para archivos grandes.
Las subidas firmadas son automáticas al usar el adaptador S3. La interfaz de administración las usa cuando están disponibles.
Adaptadores que admiten subidas firmadas:
- S3 (incluyendo R2 vía API S3)
Adaptadores que no admiten subidas firmadas:
- R2 binding (use el adaptador S3 con credenciales R2 en su lugar)
- Local
Interfaz de almacenamiento
Todos los adaptadores de almacenamiento implementan la misma interfaz:
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 consistencia permite cambiar backends de almacenamiento sin modificar el código de la aplicación.