@restnfeel/agentc-starter-kit
Version:
한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템
180 lines (149 loc) • 5.03 kB
text/typescript
import {
CDNProvider,
CDNConfig,
getCacheSettingsForMimeType,
} from "../cdn-config";
export class CloudflareCDNProvider implements CDNProvider {
private config: CDNConfig;
private baseUrl: string;
constructor(config: CDNConfig) {
this.config = config;
this.baseUrl = config.customDomain
? `https://${config.customDomain}`
: config.endpoint;
}
async upload(file: Buffer, key: string, mimeType: string): Promise<string> {
if (!this.config.enabled) {
throw new Error("CDN is disabled");
}
try {
// Cloudflare R2 또는 Images API 사용
// 실제 구현에서는 Cloudflare API 사용
const uploadUrl = `${this.config.endpoint}/api/v1/media/${key}`;
const response = await fetch(uploadUrl, {
method: "PUT",
headers: {
Authorization: `Bearer ${this.config.accessKey}`,
"Content-Type": mimeType,
...this.getCacheHeaders(mimeType),
},
body: file,
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.statusText}`);
}
return this.getUrl(key);
} catch (error) {
console.error("Cloudflare CDN upload error:", error);
throw error;
}
}
async delete(key: string): Promise<void> {
if (!this.config.enabled) return;
try {
const deleteUrl = `${this.config.endpoint}/api/v1/media/${key}`;
const response = await fetch(deleteUrl, {
method: "DELETE",
headers: {
Authorization: `Bearer ${this.config.accessKey}`,
},
});
if (!response.ok) {
throw new Error(`Delete failed: ${response.statusText}`);
}
} catch (error) {
console.error("Cloudflare CDN delete error:", error);
throw error;
}
}
async invalidate(keys: string[]): Promise<void> {
if (!this.config.enabled || keys.length === 0) return;
try {
// Cloudflare Cache Purge API
const purgeUrl = `https://api.cloudflare.com/client/v4/zones/${this.config.zone}/purge_cache`;
const urls = keys.map((key) => this.getUrl(key));
const response = await fetch(purgeUrl, {
method: "POST",
headers: {
Authorization: `Bearer ${this.config.accessKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
files: urls,
}),
});
if (!response.ok) {
throw new Error(`Cache invalidation failed: ${response.statusText}`);
}
} catch (error) {
console.error("Cloudflare CDN invalidate error:", error);
throw error;
}
}
getUrl(key: string): string {
return `${this.baseUrl}/${key}`;
}
getCacheHeaders(mimeType: string): Record<string, string> {
const cacheSettings = getCacheSettingsForMimeType(mimeType);
return {
"Cache-Control": `public, max-age=${cacheSettings.maxAge}, stale-while-revalidate=${cacheSettings.staleWhileRevalidate}, stale-if-error=${cacheSettings.staleIfError}`,
"CDN-Cache-Control": `public, max-age=${cacheSettings.maxAge}`,
"Cloudflare-CDN-Cache-Control": `public, max-age=${cacheSettings.maxAge}`,
};
}
// Cloudflare 특화 기능들
async getAnalytics(_startDate: Date, _endDate: Date) {
try {
const analyticsUrl = `https://api.cloudflare.com/client/v4/zones/${this.config.zone}/analytics/dashboard`;
const response = await fetch(analyticsUrl, {
method: "GET",
headers: {
Authorization: `Bearer ${this.config.accessKey}`,
},
});
if (!response.ok) {
throw new Error(`Analytics fetch failed: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error("Cloudflare analytics error:", error);
return null;
}
}
async optimizeImage(
key: string,
options: {
width?: number;
height?: number;
format?: "webp" | "avif" | "auto";
quality?: number;
}
) {
// Cloudflare Images 최적화 옵션
const params = new URLSearchParams();
if (options.width) params.append("w", options.width.toString());
if (options.height) params.append("h", options.height.toString());
if (options.format) params.append("f", options.format);
if (options.quality) params.append("q", options.quality.toString());
const optimizedUrl = `${this.getUrl(key)}?${params.toString()}`;
return optimizedUrl;
}
async getZoneSettings() {
try {
const settingsUrl = `https://api.cloudflare.com/client/v4/zones/${this.config.zone}/settings`;
const response = await fetch(settingsUrl, {
method: "GET",
headers: {
Authorization: `Bearer ${this.config.accessKey}`,
},
});
if (!response.ok) {
throw new Error(`Settings fetch failed: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error("Cloudflare zone settings error:", error);
return null;
}
}
}