구성 레퍼런스

이 페이지

EmDash의 주요 구성은 astro.config.mjs에 있으며, src/live.config.ts는 콘텐츠 로더를 등록합니다. 배포별 값은 환경 변수로 지정할 수도 있습니다. package.json의 작은 메타데이터 블록은 템플릿 레이블과 기존 로컬 CLI 흐름을 지원합니다.

Astro 통합

astro.config.mjs에서 EmDash를 Astro 통합으로 구성합니다.

import { defineConfig } from "astro/config";
import emdash, { local, s3 } from "emdash/astro";
import { sqlite, libsql } from "emdash/db";

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

통합 옵션

database

필수. 데이터베이스 어댑터 구성입니다. 어댑터를 하나 선택하세요.

// SQLite (Node.js)
database: sqlite({ url: "file:./data.db" });

// PostgreSQL
database: postgres({ connectionString: process.env.DATABASE_URL });

// libSQL
database: libsql({
	url: process.env.LIBSQL_DATABASE_URL,
	authToken: process.env.LIBSQL_AUTH_TOKEN,
});

// Cloudflare D1 (import from @emdash-cms/cloudflare)
database: d1({ binding: "DB" });

자세한 내용은 데이터베이스 옵션을 참고하세요.

migrations

선택. EmDash 내부 데이터베이스 마이그레이션을 런타임에 어떻게 처리할지 제어합니다. 이 옵션을 생략하면 기본값은 { runtime: "auto" }입니다.

migrations: {
	runtime: "check", // "auto" | "check" | "manual"
	dev: "auto",     // optional development override
}

auto는 보류 중인 마이그레이션을 확인하고 적용합니다. check는 실행 중인 빌드가 알고 있는 마이그레이션이 보류 중이면 503을 반환합니다(EmDash가 설치하는 이미지 엔드포인트에 대한 요청은 제외). manual은 런타임에 마이그레이션 쿼리를 전혀 수행하지 않습니다. EMDASH_MIGRATIONS_MODE는 실제로 적용되는 런타임 모드를 재정의합니다. check 또는 manual을 도입하기 전에 코어 데이터베이스 마이그레이션 관리를 참고하세요.

storage

선택. 미디어 스토리지 어댑터 구성입니다. 이 옵션을 생략하면 EmDash는 파일을 ./.emdash/uploads에 저장하고 /_emdash/api/media/file을 통해 제공합니다. 기본 로컬 디렉터리가 적합하지 않다면 어댑터를 선택하세요.

// Local filesystem (development)
storage: local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

// R2 binding (Cloudflare Workers)
storage: r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev", // optional
});

// S3-compatible (any platform) — all fields from S3_* environment variables
storage: s3()

// Or with explicit values
storage: s3({
	endpoint: "https://s3.amazonaws.com",
	bucket: "my-bucket",
	accessKeyId: process.env.S3_ACCESS_KEY_ID,
	secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
	region: "us-east-1", // optional, default: "auto"
	publicUrl: "https://cdn.example.com", // optional
});

자세한 내용은 스토리지 옵션을 참고하세요.

images

선택. 저장된 미디어를 Astro의 이미지 최적화와 통합할지 제어합니다. 기본값은 true입니다.

활성화하면 EmDash가 Astro의 이미지 엔드포인트를 감싸서 <Image>와 getImage()가 구성된 스토리지 어댑터에서 원본 바이트를 직접 읽을 수 있게 합니다. 원본 미디어 URL이 Cloudflare Access 뒤에 있어도 동작합니다. 감싼 엔드포인트에 대한 요청은 EmDash 런타임 시작을 건너뛰므로, 이 요청에서 locals.emdash에는 storage만 들어 있고, 로그인한 사용자의 경우 db가 추가됩니다. locals.user는 다른 공개 라우트와 동일하게 설정됩니다. 다른 이미지 서비스가 미디어를 처리하거나 모든 이미지를 EmDash의 엔드포인트 래퍼 없이 렌더링해야 한다면 images: false로 설정하세요.

emdash({
	images: false,
});

mediaProviders

선택. 미디어 라이브러리에 미디어 서비스를 추가합니다. 스토리지 기반의 로컬 공급자는 자동으로 계속 사용할 수 있으며, 이 배열의 각 디스크립터는 편집자가 미디어를 찾아보거나 업로드할 수 있는 장소를 하나 더 추가합니다.

다음 예제는 Cloudflare Images와 Cloudflare Stream을 추가합니다.

import { cloudflareImages, cloudflareStream } from "@emdash-cms/cloudflare";

emdash({
	mediaProviders: [cloudflareImages({}), cloudflareStream({})],
});

공급자 자격 증명은 런타임에 확인됩니다. 위의 빈 구성은 cloudflareImages(config) 및 cloudflareStream(config) 어댑터 섹션에 설명된 기본 Cloudflare 환경 변수를 사용합니다. 바인딩과 렌더링 설정은 미디어 라이브러리: 미디어 공급자를 참고하세요.

objectCache

선택. 콘텐츠 및 구성 쿼리 결과를 키/값 저장소에 캐시하여 요청마다 데이터베이스를 쿼리하지 않고 읽기를 처리합니다. 생략하면 비활성화됩니다. 어댑터를 하나 선택하세요.

// Cloudflare KV (shared across all isolates)
import { kvCache } from "@emdash-cms/cloudflare";
objectCache: kvCache({ binding: "CACHE" });

// In-memory (Node.js / development)
import { memoryCache } from "emdash/astro";
objectCache: memoryCache();

설정과 옵션은 오브젝트 캐시를 참고하세요.

middleware.outer

선택. EmDash 미들웨어 스택 전체의 바깥에 Astro 미들웨어 모듈을 등록합니다. 통합이 이를 Astro의 order: "pre"로 등록하므로 src/middleware.ts에 정의한 미들웨어보다도 먼저 실행됩니다. 캐시 히트 시 런타임과 데이터베이스 초기화를 피해야 하는 요청 게이트나 전체 응답 캐시, 또는 EmDash의 최종 HTML에 의존하는 응답 헤더에 사용하세요.

emdash({
	middleware: {
		outer: "./src/outer-middleware.ts",
	},
});

실행 순서는 다음과 같습니다.

  1. 외부 미들웨어가 await next()까지 실행됩니다.
  2. EmDash가 런타임과 데이터베이스를 초기화한 다음 설정, 인증, 요청 컨텍스트 미들웨어를 실행합니다.
  3. Astro 라우트가 렌더링됩니다.
  4. EmDash가 비주얼 편집 HTML과 보안/타이밍 헤더를 포함한 응답 변경 사항을 적용합니다.
  5. next()가 그 최종 응답과 함께 외부 미들웨어로 확정됩니다.

next()를 호출하기 전의 미들웨어에는 일반적인 Astro 요청과 플랫폼 실행 컨텍스트가 있지만, locals.emdash, locals.user, 데이터베이스, 요청 범위의 EmDash 상태는 사용할 수 없습니다. 조기에 반환한 Response는 EmDash를 완전히 건너뛰므로 필요한 보안 및 캐시 헤더를 모두 포함해야 합니다. next()가 확정된 후에는 CSP nonce를 마무리하거나, 전체 본문을 캐시하거나, Content-Length를 설정해도 안전합니다. 미들웨어가 본문을 변경한다면 기존 Content-Length 헤더를 제거하거나 다시 계산하세요.

이 훅은 Node와 Cloudflare 모두에서 Astro의 미들웨어 API를 사용합니다. 다음 최소 Cloudflare Cache API 예제는 익명 HTML 응답만 캐시하고 EmDash 초기화 전에 히트를 반환합니다.

import { waitUntil } from "cloudflare:workers";
import { defineMiddleware } from "astro:middleware";

export const onRequest = defineMiddleware(async ({ request }, next) => {
	if (request.method !== "GET" || request.headers.has("cookie")) {
		return next();
	}

	const cacheKey = new Request(request.url, { method: "GET" });
	const cached = await caches.default.match(cacheKey);
	if (cached) return cached;

	const response = await next();
	const isHtml = response.headers.get("content-type")?.includes("text/html");
	const isPrivate = response.headers.get("cache-control")?.includes("no-store");
	if (response.ok && isHtml && !isPrivate) {
		waitUntil(caches.default.put(cacheKey, response.clone()));
	}

	return response;
});

Node에서는 Redis 같은 Node 호환 캐시와 함께 같은 형태의 미들웨어를 사용하세요. 캐시 키와 우회 규칙에는 렌더링된 응답을 바꾸는 모든 요청 속성이 포함되어야 합니다.

playground

선택. 일회용 브라우저 기반 EmDash 플레이그라운드에서 사용하는 미들웨어를 활성화합니다. 세션마다 쓰기 가능한 Durable Object 데이터베이스를 만들고, 구성된 시드를 적용하며, 일반 EmDash 미들웨어가 실행되기 전에 방문자를 익명 관리자로 로그인시킵니다.

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

emdash({
	database: playgroundDatabase({ binding: "PLAYGROUND_DB" }),
	playground: {
		middlewareEntrypoint: "@emdash-cms/cloudflare/db/playground-middleware",
	},
});

이 모드에는 @emdash-cms/cloudflare와 Durable Object 바인딩이 필요합니다. 일반 설정 및 인증 미들웨어를 우회하므로, 프로덕션 CMS가 아닌 임시 데모 사이트에서만 사용하세요.

plugins

선택. Astro 사이트와 같은 프로세스에서 실행되는 플러그인 배열입니다. 네이티브 플러그인은 여기에 넣습니다. 샌드박스 호환 플러그인도 프로세스 전체 접근을 신뢰하고 격리가 필요 없다면 여기에서 실행할 수 있습니다.

다음 예제는 네이티브 플러그인을 등록합니다.

import seoPlugin from "@emdash-cms/plugin-seo";

plugins: [seoPlugin()];

네이티브 플러그인은 서버 및 프레임워크 API를 직접 사용할 수 있으므로, 패키지가 샌드박스 호환 플러그인 진입점도 제공하지 않는 한 sandboxed로 옮길 수 없습니다. 개발 및 배포 방식의 차이는 플러그인 형식 선택을 참고하세요.

sandboxed

선택. EmDash가 선언한 플러그인 API를 사용하며 격리된 런타임에서 실행되는, 샌드박스 호환 플러그인의 배열입니다. 여기에 네이티브 플러그인을 넣지 마세요. 네이티브 코드는 샌드박스가 제공하지 않는 프로세스 및 프레임워크 접근에 의존할 수 있습니다.

import thirdPartyPlugin from "third-party-emdash-plugin";
import { sandbox } from "@emdash-cms/cloudflare";

emdash({
	sandboxed: [thirdPartyPlugin()],
	sandboxRunner: sandbox(),
});

사용 가능한 샌드박스 러너가 구성되어 있지 않으면 샌드박스 플러그인은 건너뜁니다. Cloudflare 및 Node.js 러너 설정은 플러그인 샌드박스를 참고하세요.

sandboxRunner

선택. 격리된 플러그인 런타임을 시작하는 팩터리의 모듈 지정자입니다. sandboxed의 플러그인과 마켓플레이스 또는 레지스트리 플러그인에 필요합니다.

Cloudflare Workers에서는 sandbox() 어댑터를 사용하세요.

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

emdash({
	sandboxRunner: sandbox(),
});

Node.js 배포는 플러그인 샌드박스: Node.js에 설명된 workerd 러너 모듈을 사용합니다.

sandbox

선택. 구성된 샌드박스 러너가 플러그인을 격리할지 제어합니다. sandboxRunner가 구성되면 샌드박스가 활성화됩니다. 문제의 원인이 플러그인인지 샌드박스 런타임인지 진단할 때만 sandbox: false로 설정하세요.

emdash({
	sandboxRunner: sandbox(),
	sandbox: false,
});

false로 설정하면 sandboxed에 선언된 플러그인과 마켓플레이스에서 설치한 플러그인이 격리나 리소스 제한 없이 메인 서버 프로세스에서 실행됩니다. 진단이 끝나면 샌드박스를 다시 활성화하세요.

registry

선택. 플러그인 레지스트리 애그리게이터와 정책을 구성합니다. 명시적인 값이 없을 때, sandboxRunner가 구성되어 있고 sandbox가 false가 아니면 EmDash는 https://registry.emdashcms.com을 사용합니다.

registry: false로 설정하면 레지스트리 검색과 레지스트리로 설치한 플러그인이 비활성화됩니다. 이때에도 sandboxed에 선언된 플러그인과 기존 마켓플레이스 플러그인을 위해 샌드박스 러너는 계속 사용할 수 있습니다.

emdash({
	sandboxRunner: sandbox(),
	registry: false,
});

레지스트리 서비스 URL을 문자열로 전달하거나, 사이트에 모더레이션 소스나 릴리스 경과 기간 정책이 필요하면 객체를 사용하세요. 다음 예제는 객체 형식을 사용합니다.

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

emdash({
	sandboxRunner: sandbox(),
	registry: {
		aggregatorUrl: "https://registry.emdashcms.com",
		acceptLabelers: "did:web:labels.emdashcms.com",
		policy: {
			minimumReleaseAge: "48h",
			minimumReleaseAgeExclude: ["did:plc:yourfirstpartydid"],
		},
	},
});
옵션타입설명
aggregatorUrlstring레지스트리 서비스의 기본 URL입니다. 프로덕션에서는 HTTPS를 사용하세요.
acceptLabelersstring요청이 수락하는 모더레이션 서비스의 분산 식별자(DID)를 쉼표로 구분해 지정합니다(선택). DID는 안정적인 Atmosphere 계정 식별자입니다. 이 설정은 레지스트리 서비스의 정책을 재정의할 수 없습니다.
policy.minimumReleaseAgestring | number이 경과 기간보다 새로운 릴리스를 보류합니다. 기간 문자열("48h", "7d") 또는 초 단위 숫자입니다.
policy.minimumReleaseAgeExcludestring[]보류에서 제외되는 게시자 DID 또는 <did>/<plugin-slug> 쌍입니다.

릴리스 경과 기간 정책은 레지스트리가 보존된 릴리스가 하나라고 보고하고 해당 패키지를 지속적으로 관찰했음을 확인한 경우에만 패키지의 첫 릴리스를 제외합니다. 나중에 채워 넣은 패키지, 삭제된 이전 릴리스, 이력 증거의 누락이 있으면 보류가 유지됩니다. 명시적인 게시자 및 패키지 제외는 이력과 관계없이 적용됩니다.

설치 워크플로와 신뢰 모델은 플러그인 레지스트리를 참고하세요.

marketplace

사용 중단. 기존 마켓플레이스에서 설치한 플러그인을 업데이트하는 데 사용하는 기본 URL입니다. 마켓플레이스 탐색과 신규 설치는 관리자 화면에 표시되지 않습니다. 이 옵션이 구성되어 있는 동안 기존 마켓플레이스 플러그인은 계속 업데이트하고 제거할 수 있습니다.

emdash({
	marketplace: "https://marketplace.emdashcms.com",
	sandboxRunner: sandbox(),
});

프로덕션 URL은 HTTPS를 사용해야 하며, HTTP는 개발 중에 localhost와 127.0.0.1에만 허용됩니다. 모든 마켓플레이스 플러그인을 교체하거나 제거할 때까지 이 옵션을 유지한 다음 삭제하세요. 전체 절차는 마켓플레이스에서 마이그레이션을 따르세요.

fonts

선택. 관리자 UI 글꼴 구성입니다.

기본적으로 EmDash는 Astro Font API를 통해 Noto Sans를 로드합니다. 글꼴은 빌드 시점에 Google에서 다운로드되어 자체 호스팅되므로 런타임 CDN 요청이 없습니다. 기본 글꼴은 라틴, 키릴, 그리스, 데바나가리, 베트남어 문자를 지원합니다.

추가 문자 체계를 지원하려면 스크립트 이름을 전달하세요. 다음 예제는 아랍어와 일본어를 추가합니다.

emdash({
  fonts: {
    scripts: ["arabic", "japanese"],
  },
})

사용 가능한 스크립트는 arabic, armenian, bengali, chinese-simplified, chinese-traditional, chinese-hongkong, devanagari, ethiopic, farsi, georgian, gujarati, gurmukhi, hebrew, japanese, kannada, khmer, korean, lao, malayalam, myanmar, oriya, sinhala, tamil, telugu, thai, tibetan입니다.

각 스크립트는 Google Fonts의 해당 Noto Sans 변형에 대응합니다(예: "arabic"은 Noto Sans Arabic을 로드). 모든 글꼴 페이스는 하나의 font-family 이름을 공유하고 unicode-range를 사용하므로, 브라우저는 페이지의 문자에 필요한 파일만 다운로드합니다.

false로 설정하면 글꼴 주입을 완전히 비활성화하고 시스템 글꼴을 사용합니다.

emdash({
	fonts: false,
})

관리자 CSS는 --font-emdash CSS 변수를 사용합니다. 이 값은 위의 글꼴 구성으로 자동 설정됩니다.

auth

선택. 인증 어댑터입니다. EmDash의 기본 제공 로그인은 패스키이며, auth를 설정하면 외부 공급자로 대체됩니다. Cloudflare Access 어댑터인 access()는 @emdash-cms/cloudflare에서 제공합니다.

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

emdash({
	auth: access({
		teamDomain: "myteam.cloudflareaccess.com",
		audience: "your-app-audience-tag",
		roleMapping: {
			Admins: 50,
			Editors: 40,
		},
	}),
});

access() 옵션:

옵션타입기본값설명
teamDomainstring필수Cloudflare Access 팀 도메인
audiencestring—애플리케이션 Audience(AUD) 태그. Workers에서는 audienceEnvVar를 권장합니다.
audienceEnvVarstring"CF_ACCESS_AUDIENCE"런타임에 audience 태그를 읽어 올 환경 변수
autoProvisionbooleantrue첫 로그인 시 EmDash 사용자를 생성합니다
defaultRolenumber30roleMapping에 일치하지 않는 사용자의 역할 레벨(사용자 역할 참고)
syncRolesbooleanfalse프로비저닝 때만이 아니라 로그인할 때마다 roleMapping을 다시 적용합니다
roleMappingobject—IdP 그룹 이름을 EmDash 역할 레벨에 매핑합니다. 처음 일치하는 항목이 적용됩니다

authProviders

선택. 플러그인 가능한 로그인 공급자의 배열입니다(최상위 수준에서 auth와 나란히 지정). 각 항목은 아래와 같이 공급자 팩터리를 호출한 결과입니다.

import { github } from "emdash/auth/providers/github";
import { google } from "emdash/auth/providers/google";
import { atproto } from "@emdash-cms/auth-atproto";

emdash({
	authProviders: [github(), google(), atproto()],
});

기본 제공 공급자:

  • github() — EMDASH_OAUTH_GITHUB_CLIENT_ID / EMDASH_OAUTH_GITHUB_CLIENT_SECRET(또는 접두사 없는 대체 변수)을 읽습니다.
  • google() — EMDASH_OAUTH_GOOGLE_CLIENT_ID / EMDASH_OAUTH_GOOGLE_CLIENT_SECRET을 읽습니다.
  • microsoft() — EMDASH_OAUTH_MICROSOFT_CLIENT_ID / EMDASH_OAUTH_MICROSOFT_CLIENT_SECRET / EMDASH_OAUTH_MICROSOFT_TENANT_ID(또는 접두사 없는 대체 변수)를 읽습니다. { emailVerified }를 받습니다. Microsoft를 참고하세요.
  • atproto() — Atmosphere 계정 로그인(Bluesky 및 더 넓은 AT Protocol 네트워크). 환경 변수가 필요 없습니다. { allowedDIDs, allowedHandles, defaultRole }을 받습니다. Atmosphere 로그인 가이드를 참고하세요.

서드파티 패키지도 같은 AuthProviderDescriptor 형태를 사용해 자체 공급자를 등록할 수 있습니다. 로그인 공급자를 참고하세요.

mcp

선택. /_emdash/api/mcp의 Model Context Protocol(MCP) 엔드포인트를 활성화합니다. 이 엔드포인트는 기본적으로 활성화되어 있으며 베어러 토큰이 필요하므로, 활성화해도 익명 접근이 허용되지 않습니다.

사이트가 MCP 엔드포인트를 노출하지 않아야 한다면 이 옵션을 false로 설정하세요.

emdash({
	mcp: false,
});

토큰 생성과 클라이언트 구성은 MCP 서버 레퍼런스를 참고하세요.

siteUrl

브라우저에서 보이는 사이트의 공개 오리진입니다(스킴 + 호스트 + 선택적 포트, 경로 없음). 사이트를 Cloudflare Workers에 배포하는 경우가 아니라면 프로덕션 설정을 실행하기 전에 지정하세요. 그 외에는 오리진이 구성되지 않은 상태에서 설정을 완료할 수 있는 것은 루프백 개발 호스트뿐입니다.

TLS를 종료하는 리버스 프록시 뒤에서는 Astro.url이 공개 주소(https://cms.example.com) 대신 내부 주소(http://localhost:4321)를 반환합니다. 이로 인해 패스키, CSRF 오리진 일치, OAuth 리디렉션, 로그인 리디렉션, MCP 검색, 스냅샷 내보내기, 사이트맵, robots.txt, JSON-LD 구조화 데이터가 깨집니다. siteUrl을 설정하면 이 모든 문제가 한 번에 해결됩니다.

통합은 로드 시점에 이 값을 검증합니다. 프로토콜이 http: 또는 **https:**인 유효한 URL이어야 하며, 오리진으로 정규화됩니다(경로는 제거됨).

다음 예제는 공개 오리진을 설정합니다.

emdash({
	database: sqlite({ url: "file:./data.db" }),
	storage: local({
		directory: "./uploads",
		baseUrl: "/_emdash/api/media/file",
	}),
	siteUrl: "https://cms.example.com",
});

구성에 siteUrl이 없으면 EmDash는 환경 변수를 EMDASH_SITE_URL, SITE_URL 순으로 확인합니다. 공개 URL이 런타임에 설정되는 컨테이너 배포에서 유용합니다.

루프백이 아닌 호스트에서 두 소스 모두 설정되어 있지 않으면 설정이 SITE_URL_REQUIRED로 실패합니다. 이는 인증되지 않은 첫 번째 설정 요청이 이후 인증 이메일에 사용되는 오리진을 선택하는 것을 방지합니다. Cloudflare Workers에 배포한 프로덕션 빌드는 예외입니다. Cloudflare는 Worker에 바인딩된 호스트 이름으로 들어오는 요청만 라우팅하므로, 설정은 https://와 설정이 실행되는 호스트 이름을 기록합니다. 같은 빌드를 wrangler dev, astro preview, 또는 접근 가능한 주소의 자체 호스팅 workerd로 제공하는 경우에는 이런 보장이 없습니다. 그곳에서는 먼저 siteUrl 또는 EMDASH_SITE_URL을 설정하세요.

Cloudflare Workers에서는 환경 변수 대체가 process.env를 읽습니다. nodejs_compat을 사용하면, Cloudflare는 호환성 날짜가 2025-04-01 이후일 때 기본적으로 process.env를 채웁니다. 더 이른 날짜에 고정된 프로젝트는 nodejs_compat_populate_process_env도 추가해야 합니다.

// wrangler.jsonc
{
	"compatibility_date": "2026-02-24",
	"compatibility_flags": ["nodejs_compat"],
	"vars": { "EMDASH_SITE_URL": "https://cms.example.com" },
}

allowedOrigins

선택. 둘 이상의 호스트 이름에서 제공되는 배포에 대해 패스키 검증이 수락하는 추가 브라우저 오리진입니다.

siteUrl은 하나의 정규 오리진을 정의합니다. 같은 EmDash 배포가 등록 가능한 상위 도메인을 공유하는 여러 호스트 이름(예: https://example.com과 https://preview.example.com)에서 접근 가능할 때, 패스키 검증은 오리진이 siteUrl과 정확히 일치하지 않는 어서션을 거부합니다. WebAuthn은 같은 rpId 아래에서 패스키가 서브도메인 간에 유효하도록 허용하는데도 말입니다.

추가로 수락할 오리진은 astro.config.mjs의 allowedOrigins 또는 EMDASH_ALLOWED_ORIGINS 환경 변수 중 하나로 선언하세요. 정규 siteUrl은 계속 rpId의 원천이며, 여기에 나열한 항목은 검증 시점에 수락됩니다. 두 소스는 런타임에 병합되므로, 구성에서는 안정적인 오리진(버전 관리되고 코드 리뷰를 거친 것)을 선언하고 환경 변수로는 환경별 추가 항목(예: 임시 PR 미리보기)을 더할 수 있습니다.

다음 예제는 구성에서 추가 오리진 하나를 선언합니다.

emdash({
	siteUrl: "https://example.com",
	allowedOrigins: ["https://preview.example.com"],
})

동등한 값을 환경 변수로 지정할 수도 있습니다.

EMDASH_SITE_URL=https://example.com
EMDASH_ALLOWED_ORIGINS=https://preview.example.com,https://staging.example.com
검증

EmDash는 브라우저가 절대 적용하지 않을 쓸모없는 구성을 방지하기 위해 이 값들을 검증합니다.

  • 각 항목은 파싱 가능한 http: 또는 https: URL이어야 하며, 끝에 점이 없고 호스트 이름에 빈 레이블이 없어야 합니다.
  • allowedOrigins가 비어 있지 않으면 siteUrl이 (어느 소스에서든) 설정되어 있어야 하며, IP 리터럴이거나 끝에 점이 있는 호스트 이름이어서는 안 됩니다.
  • 각 오리진은 siteUrl과 같은 호스트 이름이거나 그 서브도메인이어야 합니다. (WebAuthn은 rpId가 모든 오리진의 등록 가능한 접미사일 것을 요구합니다.)

검증에 실패하면 EmDash config error in EMDASH_ALLOWED_ORIGINS: "https://other-site.com" is not a subdomain of siteUrl "https://example.com". Allowed origins must be the same hostname as siteUrl or a subdomain of it.처럼 출처가 명시된 오류가 표시됩니다.

오류가 나타나는 위치는 값을 어디에 선언했는지에 따라 달라집니다.

  • Astro 시작 시: config.allowedOrigins와 config.siteUrl이 모두 astro.config.mjs에서 오는 경우입니다. 코드의 오타가 빌드를 실패하게 합니다.
  • 첫 패스키 검증 시: 두 값 중 하나가 EMDASH_ALLOWED_ORIGINS 또는 EMDASH_SITE_URL에서 오는 경우입니다. 환경 불일치는 첫 검증 시도에서 500 오류로 나타납니다.

리버스 프록시 설정

Astro는 공개 호스트가 허용된 경우에만 **X-Forwarded-***를 반영합니다. 사용자가 접속하는 호스트 이름(및 스킴)에 대해 security.allowedDomains를 구성하세요. **astro dev**에서는 Vite가 프록시의 Host 헤더를 수락하도록 일치하는 **vite.server.allowedHosts**를 추가하세요.

먼저 allowedDomains(와 전달 헤더)를 바로잡는 것을 권장합니다. 재구성된 URL이 여전히 브라우저 오리진과 다를 때(앞단에서 TLS가 종료되고 업스트림 요청이 **http://**로 남는 일반적인 경우) **siteUrl**을 사용하세요.

앞단에 TLS가 있을 때는 개발 서버를 루프백에 바인딩하는 것(astro dev --host 127.0.0.1)만으로 충분한 경우가 많습니다. 프록시는 로컬로 연결하고 **siteUrl**은 공개 HTTPS 오리진과 일치합니다.

프록시가 클라이언트 IP 헤더를 기록한다면 EmDash의 속도 제한이 실제 클라이언트 IP를 사용할 수 있도록 trustedProxyHeaders를 설정하세요. 신뢰할 수 있는 클라이언트 IP가 없으면 인증 속도 제한은 건너뛰고, 모든 공개 댓글 제출이 하나의 속도 제한 버킷을 공유합니다(전체 방문자 합계 10분당 20개 댓글).

다음 구성은 리버스 프록시 배포를 위해 allowedDomains, vite.server.allowedHosts, siteUrl을 함께 설정합니다.

import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
	security: {
		allowedDomains: [
			{ hostname: "cms.example.com", protocol: "https" },
			{ hostname: "cms.example.com", protocol: "http" },
		],
	},
	vite: {
		server: {
			allowedHosts: ["cms.example.com"],
		},
	},
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data.db" }),
			storage: local({
				directory: "./uploads",
				baseUrl: "/_emdash/api/media/file",
			}),
			siteUrl: "https://cms.example.com",
		}),
	],
});

trustedProxyHeaders

선택. 직접 제어하는 리버스 프록시 뒤에서 실행할 때 클라이언트 IP를 확인하는 데 신뢰할 헤더입니다. 인증 속도 제한(매직 링크, 가입, 패스키, OAuth 디바이스 플로, OAuth 클라이언트 등록)과 공개 댓글 엔드포인트에서 사용됩니다.

Cloudflare에서는 요청에 첨부된 cf 객체가 자동으로 사용되므로 보통 이 옵션을 설정할 필요가 없습니다. nginx, Caddy, Traefik, Fly, Railway 등의 뒤에 있는 자체 호스팅 배포에서는 속도 제한이 실제 클라이언트 IP별로 요청을 셀 수 있도록 프록시가 기록하는 헤더를 여기에 설정하세요.

다음 예제는 nginx, Caddy, Traefik이 설정하는 x-real-ip 헤더를 신뢰합니다.

emdash({
	database: sqlite({ url: "file:./data.db" }),
	trustedProxyHeaders: ["x-real-ip"],
});

헤더는 순서대로 시도됩니다. *-forwarded-for에 일치하는 값은 쉼표로 구분된 목록으로 파싱되며 첫 번째 항목이 사용됩니다. 다음 예제는 Fly.io의 헤더를 우선하고 x-forwarded-for로 대체합니다.

emdash({
	trustedProxyHeaders: ["fly-client-ip", "x-forwarded-for"],
});

구성에 설정하지 않으면 EmDash는 EMDASH_TRUSTED_PROXY_HEADERS 환경 변수(쉼표로 구분)를 읽습니다. 구성에서 빈 배열을 명시하면 환경 변수보다 우선합니다.

maxUploadSize

선택. 허용되는 미디어 파일 업로드의 최대 크기(바이트)입니다. 직접 멀티파트 업로드와 서명된 URL 업로드 모두에 적용됩니다. 기본값은 52_428_800(50MB)입니다. 다음 예제는 한도를 100MB로 올립니다.

emdash({
	database: sqlite({ url: "file:./data.db" }),
	storage: local({
		directory: "./uploads",
		baseUrl: "/_emdash/api/media/file",
	}),
	maxUploadSize: 100 * 1024 * 1024, // 100 MB
});
값설명
number(바이트)양의 유한 정수여야 합니다
생략기본값은 50MB입니다

구성된 한도를 초과하는 업로드는 직접 업로드 경로에서는 413 Payload Too Large 응답으로, 서명된 URL 경로에서는 400 Validation Error로 거부됩니다.

admin

선택. 관리자 인터페이스의 EmDash 브랜딩을 대체합니다. 이 값들은 공개 사이트의 제목, 로고, 파비콘을 바꾸지 않습니다.

emdash({
	admin: {
		logo: "/images/agency-logo.webp",
		siteName: "Agency CMS",
		footerLabel: "AgencyX",
		favicon: "/favicon.ico",
	},
});
옵션타입설명
logostring로그인 페이지와 사이드바에 사용할 로고 URL 또는 경로
siteNamestring사이드바 헤더와 브라우저 제목에 표시되는 이름
footerLabelstring | false사이드바 버전 옆에 표시되는 레이블. 기본값은 "EmDash"이며, false는 숨깁니다
faviconstring관리자 페이지용 파비콘 URL 또는 경로

updateCheck

선택. 관리자 대시보드의 코어 업데이트 알림을 제어합니다. 기본값은 true입니다.

활성화하면 EmDash는 공개 npm 레지스트리에서 게시된 emdash 릴리스를 확인하고(최대 하루에 한 번, 요청 속도를 늦추지 않도록 응답 이후로 지연 실행), 더 새로운 버전이 있으면 관리자 대시보드에 닫을 수 있는 배너를 표시합니다. 배너를 닫으면 해당 버전에 대해서는 숨겨지며, 더 새로운 버전이 나오면 다시 나타납니다.

배너는 공개된 지 최소 24시간이 지난 가장 최신 안정 릴리스를 알려주므로, 릴리스는 출시 하루 뒤에 안내됩니다. pnpm의 minimumReleaseAge처럼 패키지 매니저의 릴리스 경과 기간 정책에 맞추려면 minimumReleaseAge를 기간 문자열("48h", "7d") 또는 초 단위 숫자로 설정하세요. "7d"로 설정하면 배너는 공개된 지 최소 일주일이 지난 가장 최신 릴리스를 안내합니다.

emdash({
	updateCheck: { minimumReleaseAge: "7d" },
})

이 확인은 https://registry.npmjs.org/emdash로 보내는 단순한 GET이며 사이트 데이터를 전혀 전송하지 않습니다. 외부 인터넷 접근이 없는 배포에서는 단순히 배너가 표시되지 않습니다. 확인을 완전히 비활성화하려면 false로 설정하세요.

emdash({
	updateCheck: false,
})

배너는 정보 제공용일 뿐입니다. EmDash를 업데이트한다는 것은 프로젝트의 emdash 패키지 버전을 올리고 다시 배포하는 것을 뜻하며, 관리자 화면에서는 이를 실행할 수 없으며, 실행해서도 안 됩니다.

toolbar

선택. 편집자 도구 모음(공개 페이지의 떠 있는 알약 모양 요소)을 어떻게 전달할지 제어합니다. 기본값은 "server"입니다.

값동작
"server"(기본값)인증된 편집자를 위해 렌더링되는 모든 HTML 응답에 서버 측에서 도구 모음이 주입됩니다.
"client"공개 HTML은 모든 방문자에게 동일합니다. 아주 작은 부트스트랩 스크립트가 관리자에 로그인한 적이 있는 브라우저에 “Edit” 알약을 표시하며, 이를 클릭하면 세션을 확인하고 _edit 쿼리 매개변수와 함께 페이지를 다시 로드합니다. 이 페이지는 항상 새로 렌더링되며(캐시되지 않음) 전체 도구 모음이 포함됩니다.
false도구 모음이나 부트스트랩 스크립트를 전혀 렌더링하지 않습니다.
emdash({
	toolbar: "client",
})

공개 HTML을 공유 캐시(Cloudflare Cache Everything / Workers Cache, Fastly, Varnish 등)를 통해 제공한다면 "client"를 사용하세요. 서버 측 주입에서는 익명 방문자가 먼저 캐시를 채우면 공개 사이트를 둘러보는 편집자가 도구 모음 없는 캐시된 익명 변형을 받게 되므로, 도구 모음이 캐시 상태에 따라 나타났다 사라집니다. 클라이언트 모드에서는 공유 가능한 HTML에 세션별로 달라지는 내용이 주입되지 않으므로 캐시가 온전히 효과를 유지하고 도구 모음도 안정적입니다.

"client" 모드에 관한 참고 사항:

  • 로그아웃한 방문자가 공유된 ?_edit URL을 열면 정규 URL로 리디렉션되므로, 이 매개변수가 초안을 유출하거나 페이지 콘텐츠로 추가 캐시 항목을 채울 수 없습니다.
  • “로그인됨” 신호는 관리자가 설정하는 비밀이 아닌 localStorage 플래그입니다. 알약은 편집 뷰에 들어가기 전에 실제 세션을 확인합니다.
  • 부트스트랩은 작은 인라인 <script>입니다. 사이트가 'unsafe-inline' 없는 엄격한 Content-Security-Policy를 보낸다면 이에 대한 해시를 추가하세요. 서버 측에서 주입되는 도구 모음에도 동일하게 적용됩니다.
  • EmDash는 세션별 내용을 전혀 주입하지 않습니다. 하지만 자체 템플릿이 Astro.locals.user에 따라 분기한다면(예: 로그인한 사용자에게 보이는 “Admin” 탐색 링크) 그 차이는 여전히 HTML에 남아 캐시를 계속 분할합니다.

어떤 모드에서든 도구 모음은 브라우저에서 × 버튼으로 닫을 수 있습니다(브라우저별로, 편집자가 다음에 관리자를 열 때까지). 미리보기 및 편집 모드 응답은 항상 Cache-Control: private, no-store와 함께 서버 측에서 렌더링됩니다.

데이터베이스 어댑터

어댑터는 emdash/db에서 가져옵니다.

import { sqlite, libsql, postgres } from "emdash/db";

sqlite(config)

Node.js의 기본 제공 데이터베이스 드라이버를 사용하는 SQLite 데이터베이스입니다. 다음 예제는 로컬 파일에 연결합니다.

옵션타입설명
urlstringfile: 접두사가 붙은 파일 경로
sqlite({ url: "file:./data.db" });

libsql(config)

libSQL 데이터베이스입니다. 다음 예제는 원격 libSQL 데이터베이스에 연결합니다.

옵션타입설명
urlstring데이터베이스 URL
authTokenstring런타임 인증 토큰(로컬 파일에서는 선택)
migrationAuthTokenEnvstring마이그레이션 토큰 변수 이름(기본값 TURSO_AUTH_TOKEN)
libsql({
	url: process.env.LIBSQL_DATABASE_URL,
	authToken: process.env.LIBSQL_AUTH_TOKEN,
});

postgres(config)

커넥션 풀링이 있는 PostgreSQL 데이터베이스입니다.

옵션타입설명
connectionStringstringPostgreSQL 연결 URL
hoststring데이터베이스 호스트
portnumber데이터베이스 포트
databasestring데이터베이스 이름
userstring데이터베이스 사용자
passwordstring데이터베이스 비밀번호
sslbooleanSSL을 활성화합니다
pool.minnumber최소 풀 크기(기본값: 0)
pool.maxnumber최대 풀 크기(기본값: 10)
pool.connectionTimeoutMillisnumber최대 연결 대기 시간(pg 기본값: 0, 타임아웃 없음)
pool.idleTimeoutMillisnumber유휴 클라이언트 수명(pg 기본값: 10,000ms)
migrationConnectionStringEnvstring마이그레이션 연결 문자열 변수 이름(기본값 DATABASE_URL)

다음 예제는 연결 문자열로 연결합니다.

postgres({ connectionString: process.env.DATABASE_URL });

d1(config)

Cloudflare D1 데이터베이스입니다. @emdash-cms/cloudflare에서 가져옵니다.

옵션타입기본값설명
bindingstring—wrangler.jsonc의 D1 바인딩 이름
sessionstring"disabled"읽기 복제 모드: "disabled", "auto", "primary-first"
bookmarkCookiestring"__em_d1_bookmark"세션 북마크용 쿠키 이름
coalescebooleanfalse같은 이벤트 루프 턴의 동시 읽기를 일괄 처리합니다. "disabled"가 아닌 세션 모드가 필요합니다

다음 예제는 기본 바인딩과 읽기 복제본을 활성화한 바인딩을 보여 줍니다.

// Basic
d1({ binding: "DB" });

// With read replicas
d1({ binding: "DB", session: "auto" });

session이 "auto" 또는 "primary-first"이면 EmDash는 D1 Sessions API를 사용해 읽기 쿼리를 가까운 복제본으로 라우팅합니다. 인증된 사용자는 북마크 기반의 read-your-writes 일관성을 얻습니다. 자세한 내용은 데이터베이스 옵션 — 읽기 복제본을 참고하세요.

hyperdrive(config?)

Cloudflare Hyperdrive 바인딩을 통한 PostgreSQL입니다. 이 어댑터는 @emdash-cms/cloudflare에서 가져옵니다.

옵션타입기본값설명
bindingstring"HYPERDRIVE"쿼리 캐싱을 비활성화한 기본 Hyperdrive 바인딩
cachedBindingstring—익명 공개 읽기를 위한, 캐싱을 활성화한 선택적인 두 번째 바인딩
preferUncachedAfterWriteMsnumber60_000cachedBinding이 설정된 경우 콘텐츠 쓰기 후 공개 읽기가 기본 바인딩을 사용하는 기간
migrationConnectionStringEnvstring기본 바인딩에서 파생emdash migrate가 사용하는 직접 PostgreSQL URL을 담은 환경 변수
maxnumber5하나의 Worker 아이솔레이트에서 Hyperdrive로의 최대 연결 수

다음 예제는 인증된 요청과 쓰기를 캐시되지 않는 바인딩으로 보내고, 익명 공개 읽기는 캐시되는 바인딩을 사용할 수 있게 합니다.

hyperdrive({
	binding: "HYPERDRIVE",
	cachedBinding: "HYPERDRIVE_CACHED",
	preferUncachedAfterWriteMs: 60_000,
});

두 바인딩은 같은 데이터베이스를 가리켜야 합니다. pg 8.16.3 이상을 설치하고, nodejs_compat 호환성 플래그를 활성화하며, 배포 마이그레이션을 위해 직접 데이터베이스 URL을 구성하세요. 전체 Worker 및 마이그레이션 설정은 데이터베이스 옵션: Hyperdrive를 참고하세요.

durableObjects(config)

CMS를 SQLite 기반의 단일 Durable Object에 저장합니다. 이 어댑터는 @emdash-cms/cloudflare에서 가져옵니다.

옵션타입기본값설명
bindingstring필수EmDashDB 클래스용 Durable Object 네임스페이스 바인딩
namestring"emdash"싱글턴 객체 이름. 하나의 바인딩 뒤에서 여러 데이터베이스를 격리할 때만 변경하세요
sessionstring"disabled""auto"는 익명 읽기를 복제본으로, 쓰기를 기본 인스턴스로 라우팅합니다
bookmarkCookiestring"__em_do_bookmark""auto" 모드에서 read-your-writes 일관성에 사용되는 쿠키
durableObjects({ binding: "DB_DO", session: "auto" });

복제본 라우팅에는 experimental 및 replica_routing 호환성 플래그와 함께, wrangler.jsonc의 Durable Object 클래스 및 마이그레이션 항목이 필요합니다.

previewDatabase(config)

미리보기 세션마다 격리된 스냅샷 데이터베이스를 Durable Object에 하나씩 만듭니다. 유일한 옵션은 필수 binding 이름입니다.

previewDatabase({ binding: "PREVIEW_DB" });

이 어댑터는 프로덕션 사이트의 기본 데이터베이스가 아니라 미리보기 인프라를 위한 것입니다.

playgroundDatabase(config)

플레이그라운드 세션마다 시드가 적용된 쓰기 가능한 데이터베이스를 Durable Object에 하나씩 만듭니다. playground 통합 옵션과 함께 사용하세요.

playgroundDatabase({ binding: "PLAYGROUND_DB" });

필수 binding은 플레이그라운드 Durable Object 네임스페이스를 지정합니다. 이 어댑터는 일회용 데모 사이트에만 사용하세요.

스토리지 어댑터

local과 s3는 emdash/astro에서 가져옵니다. r2 어댑터는 @emdash-cms/cloudflare에서 가져옵니다.

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

local(config)

로컬 파일 시스템 스토리지입니다. 다음 예제는 로컬 디렉터리에서 업로드를 제공합니다.

옵션타입설명
directorystring디렉터리 경로
baseUrlstring파일 제공용 기본 URL
local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

r2(config)

Cloudflare R2 바인딩입니다. 다음 예제는 공개 URL이 있는 R2 바인딩을 사용합니다.

옵션타입설명
bindingstringR2 바인딩 이름
publicUrlstring선택적 공개 URL
r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev",
});

s3(config?)

S3 호환 스토리지입니다. 모든 구성 필드는 선택 사항입니다. s3({...})에서 생략한 필드는 Node 프로세스가 시작될 때 일치하는 S3_* 환경 변수에서 확인됩니다. 명시적인 값이 항상 우선합니다.

구성 값과 환경 변수 값을 병합한 뒤에는 endpoint와 bucket이 필수입니다. 자격 증명 중 하나라도 설정되어 있으면 accessKeyId와 secretAccessKey가 모두 필수입니다. 값이 없으면 MISSING_S3_CONFIG 오류 코드로 시작이 실패합니다.

사전 요구 사항: 프로젝트에 @aws-sdk/client-s3와 @aws-sdk/s3-request-presigner를 설치하세요. EmDash 코어는 AWS SDK를 번들로 포함하지 않습니다. 자세한 내용은 스토리지 옵션: S3 호환 스토리지를 참고하세요.

옵션타입설명
endpointstringS3 엔드포인트 URL(S3_ENDPOINT)
bucketstring버킷 이름(S3_BUCKET)
accessKeyIdstring액세스 키(S3_ACCESS_KEY_ID)
secretAccessKeystring시크릿 키(S3_SECRET_ACCESS_KEY)
regionstring리전, 기본값 "auto"(S3_REGION)
publicUrlstring선택적 CDN URL(S3_PUBLIC_URL)

다음 예제는 모든 필드를 환경에서 확인하거나, 구성과 환경을 섞어 쓰거나, 모든 필드를 명시적으로 전달합니다.

// All fields from S3_* environment variables (Node container deployments)
s3()

// Mix: CDN from config, rest from environment
s3({ publicUrl: "https://cdn.example.com" })

// All explicit
s3({
	endpoint: "https://xxx.r2.cloudflarestorage.com",
	bucket: "media",
	accessKeyId: process.env.R2_ACCESS_KEY_ID,
	secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
	publicUrl: "https://cdn.example.com",
})

런타임 환경 변수 확인은 Node 전용 기능입니다. Cloudflare Workers에서는 시크릿과 변수가 process.env가 아니라 fetch 핸들러의 env 매개변수를 통해 노출되므로 S3_* 환경 변수는 인식되지 않습니다. Workers 배포에서는 r2(config) 어댑터를 사용하거나 s3({...})에 명시적인 값을 전달하세요. 자세한 내용은 스토리지 옵션을 참고하세요.

오브젝트 캐시 어댑터

이 중 하나를 objectCache 옵션에 전달하세요.

kvCache(config)

모든 아이솔레이트가 공유하는 Cloudflare KV 백엔드입니다. @emdash-cms/cloudflare에서 가져옵니다.

kvCache({
	binding: "CACHE", // KV binding name (required)
	defaultTtl: 3600, // entry TTL in seconds (optional, KV minimum 60)
	revalidate: 1000, // cross-isolate staleness window in ms (optional)
	timeout: 2000, // per-op timeout in ms before a miss (optional, 0 disables)
	keyPrefix: "em", // cache key prefix (optional)
})

memoryCache(config?)

Node.js와 개발용 인프로세스 백엔드입니다. emdash/astro에서 가져옵니다.

memoryCache({
	defaultTtl: 3600, // entry TTL in seconds (optional)
	revalidate: 1000, // staleness window in ms (optional)
	maxEntries: 1000, // max cached keys before eviction (optional)
	keyPrefix: "em", // cache key prefix (optional)
})

설정과 동작은 오브젝트 캐시를 참고하세요.

인증 및 샌드박스 어댑터

이 어댑터들은 auth 및 sandboxRunner 통합 옵션에 쓰이는 값을 반환합니다.

access(config)

기본 제공 패스키 로그인을 Cloudflare Access 인증으로 대체합니다. @emdash-cms/cloudflare에서 가져와 결과를 auth에 전달하세요.

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

emdash({
	auth: access({
		teamDomain: "myteam.cloudflareaccess.com",
		audienceEnvVar: "CF_ACCESS_AUDIENCE",
	}),
});

teamDomain은 필수입니다. 이 어댑터는 애플리케이션 audience를 audience 또는 audienceEnvVar가 지정한 변수에서 읽을 수 있으며, autoProvision, defaultRole, syncRoles, roleMapping도 받습니다. 이들의 기본값과 역할 동작은 auth 옵션에 설명되어 있습니다.

sandbox()

플러그인 샌드박스 러너로 Cloudflare Worker Loader를 선택합니다. @emdash-cms/cloudflare에서 가져와 반환값을 sandboxRunner에 전달하세요.

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

emdash({
	sandboxRunner: sandbox(),
});

사이트에는 Worker Loader 바인딩과 플러그인 브리지 진입점도 필요합니다. 이러한 배포 설정은 플러그인 샌드박스: Cloudflare Workers를 참고하세요.

미디어 공급자 어댑터

미디어 공급자 디스크립터를 mediaProviders에 전달하세요. 기본 제공되는 두 Cloudflare 공급자는 모두 @emdash-cms/cloudflare에서 가져옵니다.

아래의 각 *EnvVar 옵션은 환경 변수의 이름을 지정합니다. 공급자는 해당 이름의 Cloudflare Workers 바인딩, 그다음 Node 어댑터의 process.env 순서로 읽습니다. 대응하는 직접 옵션(accountId, accountHash, apiToken)은 항상 두 가지보다 우선합니다.

cloudflareImages(config)

이미지 에셋을 찾아보고, 업로드하고, 삭제하고, 전송하기 위해 Cloudflare Images를 추가합니다.

옵션타입기본값설명
accountIdstringCF_ACCOUNT_ID에서Cloudflare 계정 ID
accountIdEnvVarstring"CF_ACCOUNT_ID"accountId를 생략했을 때 사용하는 변수
accountHashstringCF_IMAGES_ACCOUNT_HASH에서전송 URL에 사용되는 계정 해시
accountHashEnvVarstring"CF_IMAGES_ACCOUNT_HASH"accountHash를 생략했을 때 사용하는 변수
apiTokenstringCF_IMAGES_TOKEN에서Cloudflare Images 읽기 및 편집 권한이 있는 토큰
apiTokenEnvVarstring"CF_IMAGES_TOKEN"apiToken을 생략했을 때 사용하는 변수
deliveryDomainstringimagedelivery.net이미지 전송용 사용자 지정 호스트 이름
defaultVariantstring"public"표시에 사용하는 이미지 변형
mediaProviders: [cloudflareImages({ defaultVariant: "public" })];

cloudflareStream(config)

비디오 에셋을 찾아보고, 검색하고, 업로드하고, 삭제하고, 재생하기 위해 Cloudflare Stream을 추가합니다.

옵션타입기본값설명
accountIdstringCF_ACCOUNT_ID에서Cloudflare 계정 ID
accountIdEnvVarstring"CF_ACCOUNT_ID"accountId를 생략했을 때 사용하는 변수
apiTokenstringCF_STREAM_TOKEN에서Cloudflare Stream 읽기 및 편집 권한이 있는 토큰
apiTokenEnvVarstring"CF_STREAM_TOKEN"apiToken을 생략했을 때 사용하는 변수
customerSubdomainstringCloudflare 기본값Stream 전송용 사용자 지정 호스트 이름
controlsbooleantrue플레이어 컨트롤을 표시합니다
autoplaybooleanfalse재생을 자동으로 시작합니다
loopbooleanfalse재생을 반복합니다
mutedbooleanfalse, 자동 재생이면 true재생을 음소거합니다
mediaProviders: [cloudflareStream({ controls: true })];

필요한 바인딩과 렌더링 컴포넌트는 미디어 라이브러리: 미디어 공급자를 참고하세요.

라이브 컬렉션

src/live.config.ts에서 EmDash 로더를 구성합니다.

import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";

export const collections = {
	_emdash: defineLiveCollection({
		loader: emdashLoader(),
	}),
};

로더 옵션

emdashLoader() 함수는 인수를 받지 않습니다.

emdashLoader();

환경 변수

EmDash는 다음 환경 변수를 따릅니다.

변수설명
EMDASH_SITE_URL브라우저에서 보이는 공개 오리진(SITE_URL로 대체)
EMDASH_ALLOWED_ORIGINS패스키 검증이 수락하는 추가 오리진의 쉼표로 구분된 목록(다중 서브도메인 배포용).
EMDASH_DATABASE_URL데이터베이스 URL을 재정의합니다
EMDASH_ENCRYPTION_KEY플러그인 시크릿을 저장 시 암호화하는 키. 운영자가 제공하며 데이터베이스에는 저장되지 않습니다.
EMDASH_PREVIEW_SECRET미리보기 HMAC 시크릿의 선택적 재정의. 설정하지 않으면 사이트별 안정적인 값이 생성되어 데이터베이스에 저장됩니다.
EMDASH_IP_SALT댓글 작성자 IP 해시 솔트의 선택적 재정의. 설정하지 않으면 사이트별 안정적인 값이 생성되어 데이터베이스에 저장됩니다.
EMDASH_AUTH_SECRET레거시. 설정되어 있으면 IP 솔트의 소스로 사용됩니다. 기존 설치는 업그레이드 후에도 댓글 작성자 IP 해시를 안정적으로 유지하려면 이 값을 유지해야 합니다.
EMDASH_TURNSTILE_SECRET_KEYCloudflare Turnstile 시크릿 키(TURNSTILE_SECRET_KEY로 대체). 설정하면 댓글 제출에 유효한 Turnstile 토큰이 포함되어야 합니다. <CommentForm>의 turnstileSiteKey prop과 함께 사용하세요.
EMDASH_URL스키마 동기화용 원격 EmDash URL

다음 명령으로 암호화 키를 생성합니다.

npx emdash secrets generate

package.json 구성

템플릿과 사이트는 package.json의 emdash 키 아래에 선택적 메타데이터를 선언할 수 있습니다.

{
	"emdash": {
		"label": "My Blog Template",
		"schema": ".emdash/schema.sql",
		"seed": ".emdash/seed.json"
	}
}
옵션설명
label표시용 템플릿 이름
schemaemdash init이 읽는 선택적 SQL 스키마
seed시드 JSON 파일 경로

TypeScript 구성

로컬 개발 중에 Astro 통합은 프로젝트 루트에 emdash-env.d.ts를 생성하고 스키마 변경 후에 갱신합니다. 이 파일은 emdash 모듈을 확장하므로, 표준 getEmDashCollection() 및 getEmDashEntry() import는 경로 별칭 없이도 로컬 컬렉션 필드를 추론합니다.

별도의 emdash types 명령은 실행 중인 로컬 또는 원격 인스턴스에서 스키마를 가져와 기본적으로 .emdash/types.ts에 기록합니다. 애플리케이션 코드가 그 독립 실행형 출력을 직접 import할 때만 별칭을 추가하세요.

{
	"compilerOptions": {
		"paths": {
			"@emdash-cms/types": ["./.emdash/types.ts"]
		}
	}
}

다음 명령으로 원격 스키마의 독립 실행형 타입을 생성합니다.

npx emdash types