@restnfeel/agentc-starter-kit
Version:
한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템
243 lines (240 loc) • 9.47 kB
JavaScript
import { createClient } from '@supabase/supabase-js';
class SupabaseStorageManager {
constructor(config) {
this.client = createClient(config.url, config.anonKey);
this.bucket = config.bucket;
}
async initializeBucket() {
try {
// Check if bucket exists
const { data: buckets, error } = await this.client.storage.listBuckets();
if (error) {
throw new Error(`Failed to list buckets: ${error.message}`);
}
const bucketExists = buckets === null || buckets === void 0 ? void 0 : buckets.some((bucket) => bucket.name === this.bucket);
if (!bucketExists) {
// Create bucket if it doesn't exist
const { error: createError } = await this.client.storage.createBucket(this.bucket, {
public: false, // Private bucket for security
allowedMimeTypes: [
"application/pdf",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/msword",
"text/plain",
"text/markdown",
],
fileSizeLimit: 50 * 1024 * 1024, // 50MB limit
});
if (createError) {
throw new Error(`Failed to create bucket: ${createError.message}`);
}
}
}
catch (error) {
console.warn("Failed to initialize bucket:", error);
// Continue execution - bucket might already exist
}
}
async uploadDocument(file, fileName, metadata) {
try {
const timestamp = new Date().toISOString();
const sanitizedFileName = this.sanitizeFileName(fileName);
const path = `documents/${timestamp}_${sanitizedFileName}`;
const uploadData = file instanceof File ? file : file;
const { data, error } = await this.client.storage
.from(this.bucket)
.upload(path, uploadData, {
cacheControl: "3600",
upsert: false,
metadata: {
...metadata,
originalName: fileName,
uploadedAt: timestamp,
},
});
if (error) {
throw new Error(`Upload failed: ${error.message}`);
}
const { data: urlData } = this.client.storage
.from(this.bucket)
.getPublicUrl(data.path);
const fileSize = file instanceof File ? file.size : file.length;
const mimeType = this.getMimeType(fileName);
return {
id: this.generateDocumentId(data.path),
path: data.path,
url: urlData.publicUrl,
size: fileSize,
mimeType,
uploadedAt: new Date(timestamp),
};
}
catch (error) {
throw new Error(`Failed to upload document: ${error}`);
}
}
async downloadDocument(path) {
try {
const { data, error } = await this.client.storage
.from(this.bucket)
.download(path);
if (error) {
throw new Error(`Download failed: ${error.message}`);
}
if (!data) {
throw new Error("No data received from download");
}
return Buffer.from(await data.arrayBuffer());
}
catch (error) {
throw new Error(`Failed to download document: ${error}`);
}
}
async deleteDocument(path) {
try {
const { error } = await this.client.storage
.from(this.bucket)
.remove([path]);
if (error) {
throw new Error(`Delete failed: ${error.message}`);
}
}
catch (error) {
throw new Error(`Failed to delete document: ${error}`);
}
}
async listDocuments(prefix) {
try {
const { data, error } = await this.client.storage
.from(this.bucket)
.list(prefix || "documents");
if (error) {
throw new Error(`List failed: ${error.message}`);
}
return data.map((file) => {
var _a;
return ({
name: file.name,
id: file.id || this.generateDocumentId(file.name),
updated_at: file.updated_at || "",
size: ((_a = file.metadata) === null || _a === void 0 ? void 0 : _a.size) || 0,
metadata: file.metadata || {},
});
});
}
catch (error) {
throw new Error(`Failed to list documents: ${error}`);
}
}
async createDocumentVersion(originalPath, newFile, version, metadata) {
try {
const pathParts = originalPath.split("/");
const originalFileName = pathParts[pathParts.length - 1];
const baseFileName = originalFileName.replace(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z_/, "");
const timestamp = new Date().toISOString();
const versionPath = `documents/versions/${timestamp}_v${version}_${baseFileName}`;
const uploadData = newFile instanceof File ? newFile : newFile;
const { data, error } = await this.client.storage
.from(this.bucket)
.upload(versionPath, uploadData, {
cacheControl: "3600",
upsert: false,
metadata: {
...metadata,
originalPath,
version,
createdAt: timestamp,
},
});
if (error) {
throw new Error(`Version upload failed: ${error.message}`);
}
const fileSize = newFile instanceof File ? newFile.size : newFile.length;
return {
id: this.generateDocumentId(data.path),
documentId: this.generateDocumentId(originalPath),
version,
path: data.path,
size: fileSize,
uploadedAt: new Date(timestamp),
metadata,
};
}
catch (error) {
throw new Error(`Failed to create document version: ${error}`);
}
}
async getDocumentVersions(documentId) {
try {
const { data, error } = await this.client.storage
.from(this.bucket)
.list("documents/versions");
if (error) {
throw new Error(`Failed to list versions: ${error.message}`);
}
// Filter versions for the specific document
const versions = data
.filter((file) => {
var _a;
return ((_a = file.metadata) === null || _a === void 0 ? void 0 : _a.originalPath) &&
this.generateDocumentId(file.metadata.originalPath) === documentId;
})
.map((file) => {
var _a, _b, _c;
return ({
id: this.generateDocumentId(file.name),
documentId,
version: ((_a = file.metadata) === null || _a === void 0 ? void 0 : _a.version) || 1,
path: `documents/versions/${file.name}`,
size: ((_b = file.metadata) === null || _b === void 0 ? void 0 : _b.size) || 0,
uploadedAt: new Date(((_c = file.metadata) === null || _c === void 0 ? void 0 : _c.createdAt) || file.updated_at),
metadata: file.metadata,
});
})
.sort((a, b) => b.version - a.version);
return versions;
}
catch (error) {
throw new Error(`Failed to get document versions: ${error}`);
}
}
sanitizeFileName(fileName) {
return fileName
.replace(/[^a-zA-Z0-9.-]/g, "_")
.replace(/_{2,}/g, "_")
.toLowerCase();
}
generateDocumentId(path) {
return Buffer.from(path)
.toString("base64")
.replace(/[^a-zA-Z0-9]/g, "");
}
getMimeType(fileName) {
var _a;
const extension = (_a = fileName.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
const mimeTypes = {
pdf: "application/pdf",
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
doc: "application/msword",
txt: "text/plain",
md: "text/markdown",
};
return mimeTypes[extension || ""] || "application/octet-stream";
}
async getStorageStats() {
try {
const files = await this.listDocuments();
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
return {
totalFiles: files.length,
totalSize,
bucketName: this.bucket,
};
}
catch (error) {
throw new Error(`Failed to get storage stats: ${error}`);
}
}
}
export { SupabaseStorageManager };
//# sourceMappingURL=supabase.js.map