Opciones de almacenamiento

En esta página

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

AlmacenamientoIdeal paraCaracterísticas
R2 BindingCloudflare WorkersSin configuración, rápido
S3Cualquier plataformaSubidas firmadas, soporte CDN
LocalDesarrolloAlmacenamiento 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ónTipoDescripción
bindingstringNombre del binding R2 en wrangler.jsonc
publicUrlstringURL 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:

  1. Panel de Cloudflare > R2 > su bucket
  2. Habilitar acceso público en Configuración
  3. 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ónTipoRequeridoDescripción
endpointstringURL del endpoint S3
bucketstringNombre del bucket
accessKeyIdstringno*Clave de acceso
secretAccessKeystringno*Clave secreta
regionstringnoRegión (por defecto: "auto")
publicUrlstringnoURL 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 entornoCampoNotas
S3_ENDPOINTendpointDebe ser una URL http/https válida
S3_BUCKETbucket
S3_ACCESS_KEY_IDaccessKeyId
S3_SECRET_ACCESS_KEYsecretAccessKey
S3_REGIONregionPor defecto "auto"
S3_PUBLIC_URLpublicUrlPrefijo 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ónTipoDescripción
directorystringRuta del directorio de almacenamiento
baseUrlstringURL 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.