콘텐츠로 이동

설정 참조

EmDash는 두 개의 파일을 통해 구성됩니다: 통합을 위한 astro.config.mjs와 콘텐츠 컬렉션을 위한 src/live.config.ts입니다.

EmDash를 Astro 통합으로 구성합니다:

astro.config.mjs
import { defineConfig } from "astro/config";
import emdash, { local, r2, s3 } from "emdash/astro";
import { sqlite, libsql, d1 } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
plugins: [],
}),
],
});

필수. 데이터베이스 어댑터 구성입니다.

// 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 (@emdash-cms/cloudflare에서 임포트)
database: d1({ binding: "DB" });

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

필수. 미디어 저장소 어댑터 구성입니다.

// Local filesystem (development)
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});
// R2 바인딩 (Cloudflare Workers)
storage: r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev", // optional
});
// S3 호환 (모든 플랫폼)
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
});

자세한 내용은 저장소 옵션을 참조하세요.

선택 사항. EmDash 플러그인 배열입니다.

import seoPlugin from "@emdash-cms/plugin-seo";
plugins: [seoPlugin()];

선택 사항. 인증 구성입니다.

auth: {
// Self-signup configuration
selfSignup: {
domains: ["example.com"],
defaultRole: 20, // Contributor
},
// OAuth providers
oauth: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
},
// Session configuration
session: {
maxAge: 30 * 24 * 60 * 60, // 30 days
sliding: true, // Reset expiry on activity
},
// OR use Cloudflare Access (exclusive mode)
cloudflareAccess: {
teamDomain: "myteam.cloudflareaccess.com",
audience: "your-app-audience-tag",
autoProvision: true,
defaultRole: 30,
syncRoles: false,
roleMapping: {
"Admins": 50,
"Editors": 40,
},
},
}

사용자의 이메일 도메인이 허용된 경우 자체 등록을 허용합니다.

옵션타입기본값설명
domainsstring[][]허용된 이메일 도메인
defaultRolenumber20자체 등록 사용자의 역할
selfSignup: {
domains: ["example.com", "acme.org"],
defaultRole: 20, // Contributor
}

OAuth 로그인 공급자를 구성합니다.

oauth: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
}

세션 구성입니다.

옵션타입기본값설명
maxAgenumber2592000 (30일)세션 수명(초 단위)
slidingbooleantrue활동 시 만료 시간 재설정

패스키 대신 Cloudflare Access를 인증 공급자로 사용합니다.

옵션타입기본값설명
teamDomainstring필수귀하의 Access 팀 도메인
audiencestring필수애플리케이션 대상 (AUD) 태그
autoProvisionbooleantrue첫 로그인 시 사용자 생성
defaultRolenumber30새 사용자의 기본 역할
syncRolesbooleanfalse각 로그인 시 역할 업데이트
roleMappingobject—IdP 그룹을 역할에 매핑

선택 사항. 완전한 브라우저가 접근하는 오리진(스킴 + 호스트 + 선택적 포트, 경로 없음)을 전달하여 WebAuthn rpId 및 **origin**이 사용자 브라우저가 clientData.origin에서 보내는 것과 일치하도록 합니다.

기본적으로 패스키는 Astro.url / **request.url**을 따릅니다. TLS 종료 리버스 프록시 뒤에서 앱은 종종 내부 홉에서 **http://**을 보는 반면, 브라우저 탭은 https://,이거나 재구성된 호스트가 공개 이름과 일치하지 않아 패스키 검증이 실패합니다. passkeyPublicOrigin을 사용자가 주소창에 입력하는 오리진(예: https://cms.example.com 또는 https://cms.example.com:8443)으로 설정하세요.

통합은 로드 시 이 값을 검증합니다: 유효한 URL이어야 하며 http: 또는 https: 프로토콜을 가져야 하고 **origin**으로 정규화됩니다.

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

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

allowedDomains(및 전달된 헤더)를 먼저 수정하는 것을 선호하세요; 재구성된 URL이 여전히 브라우저 오리진과 다를 때(일반적으로 TLS가 앞단에서 종료되고 업스트림 요청이 **http://**로 유지될 때) **passkeyPublicOrigin**을 사용하세요.

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

js title="astro.config.mjs (excerpt)"
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",
}),
passkeyPublicOrigin: "https://cms.example.com",
}),
],
});

emdash/db에서 임포트합니다:

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

better-sqlite3를 사용하는 SQLite 데이터베이스입니다.

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

libSQL 데이터베이스입니다.

옵션타입설명
urlstring데이터베이스 URL
authTokenstring인증 토큰 (로컬 파일의 경우 선택 사항)
libsql({
url: process.env.LIBSQL_DATABASE_URL,
authToken: process.env.LIBSQL_AUTH_TOKEN,
});

연결 풀링이 있는 PostgreSQL 데이터베이스입니다.

옵션타입설명
connectionStringstringPostgreSQL 연결 URL
hoststring데이터베이스 호스트
portnumber데이터베이스 포트
databasestring데이터베이스 이름
userstring데이터베이스 사용자
passwordstring데이터베이스 비밀번호
sslbooleanSSL 활성화
pool.minnumber최소 풀 크기 (기본값: 0)
pool.maxnumber최대 풀 크기 (기본값: 10)
postgres({ connectionString: process.env.DATABASE_URL });

Cloudflare D1 데이터베이스입니다. @emdash-cms/cloudflare에서 임포트합니다.

옵션유형기본값설명
bindingstring—wrangler.jsonc의 D1 바인딩 이름
sessionstring"disabled"읽기 복제 모드: "disabled", "auto", "primary-first"
bookmarkCookiestring"__ec_d1_bookmark"세션 북마크용 쿠키 이름
// Basic
d1({ binding: "DB" });
// 읽기 복제본과 함께
d1({ binding: "DB", session: "auto" });

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

emdash/astro에서 가져오기:

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

로컬 파일 시스템 스토리지.

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

Cloudflare R2 바인딩.

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

S3 호환 스토리지.

옵션유형설명
endpointstringS3 엔드포인트 URL
bucketstring버킷 이름
accessKeyIdstring액세스 키
secretAccessKeystring시크릿 키
regionstring리전 (기본값: "auto")
publicUrlstring선택적 CDN URL
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",
});

src/live.config.ts에서 EmDash 로더 구성:

ts title="src/live.config.ts"
import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";
export const collections = {
_emdash: defineLiveCollection({
loader: emdashLoader(),
}),
};

emdashLoader() 함수는 선택적 구성을 허용합니다:

emdashLoader({
// Currently no options - reserved for future use
});

EmDash는 다음 환경 변수를 준수합니다:

변수설명
EMDASH_DATABASE_URL데이터베이스 URL 재정의
EMDASH_AUTH_SECRET패스키 인증용 시크릿
EMDASH_PREVIEW_SECRET미리보기 토큰 생성용 시크릿
EMDASH_URL스키마 동기화용 원격 EmDash URL

인증 시크릿 생성:

Terminal window
npx emdash auth secret

package.json의 선택적 구성:

json title="package.json"
{
"emdash": {
"label": "내 블로그 템플릿",
"description": "깔끔하고 미니멀한 블로그 템플릿",
"seed": ".emdash/seed.json",
"url": "https://my-site.pages.dev",
"preview": "https://emdash-blog.pages.dev"
}
}
옵션설명
label표시용 템플릿 이름
description템플릿 설명
seed시드 JSON 파일 경로
url스키마 동기화용 원격 URL
preview템플릿 미리보기용 데모 사이트 URL

EmDash는 .emdash/types.ts에 타입을 생성합니다. tsconfig.json에 추가:

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

타입 생성:

Terminal window
npx emdash types