UNPKG

@smartsamurai/krapi-sdk

Version:

KRAPI TypeScript SDK - Easy-to-use client SDK for connecting to self-hosted KRAPI servers (like Appwrite SDK)

456 lines (416 loc) 12.1 kB
/** * Storage HTTP Client for KRAPI SDK * * HTTP-based storage methods for frontend applications. * Provides file upload, download, management, and folder operations. * * @module http-clients/storage-http-client * @example * const client = new StorageHttpClient({ baseUrl: 'https://api.example.com' }); * const file = await client.uploadFile('project-id', fileObject); */ import { ApiResponse, PaginatedResponse } from "../core"; import { KrapiError } from "../core/krapi-error"; import { StoredFile, FileFolder, FileVersion, FilePermission, FileFilter, StorageStatistics, FileUrlRequest, } from "../storage-service"; import { BaseHttpClient } from "./base-http-client"; /** * Storage HTTP Client * * HTTP client for file storage operations. * * @class StorageHttpClient * @extends {BaseHttpClient} * @example * const client = new StorageHttpClient({ baseUrl: 'https://api.example.com' }); * const file = await client.uploadFile('project-id', fileObject); */ export class StorageHttpClient extends BaseHttpClient { async getStorageInfo(projectId: string): Promise<{ total_files: number; total_size: number; storage_used_percentage: number; quota: number; }> { const response = await this.get<{ total_files: number; total_size: number; storage_used_percentage: number; quota: number; }>(`/projects/${projectId}/storage/info`); if (!response.data) { throw KrapiError.internalError("Storage info response is missing data"); } return response.data; } // File Management async uploadFile( projectId: string, file: File, options?: { folder_id?: string; tags?: string[]; metadata?: Record<string, unknown>; is_public?: boolean; } ): Promise<ApiResponse<StoredFile>> { const formData = new FormData(); formData.append("file", file); if (options?.folder_id) { formData.append("folder_id", options.folder_id); } if (options?.tags) { formData.append("tags", JSON.stringify(options.tags)); } if (options?.metadata) { formData.append("metadata", JSON.stringify(options.metadata)); } if (options?.is_public !== undefined) { formData.append("is_public", options.is_public.toString()); } return this.post<StoredFile>( `/projects/${projectId}/storage/upload`, formData ); } async downloadFile( projectId: string, fileId: string ): Promise<ApiResponse<Blob>> { return this.get<Blob>( `/projects/${projectId}/storage/files/${fileId}/download` ); } async getFile( projectId: string, fileId: string ): Promise<ApiResponse<StoredFile>> { return this.get<StoredFile>( `/projects/${projectId}/storage/files/${fileId}` ); } async getMetadata( projectId: string, fileId: string ): Promise<ApiResponse<StoredFile>> { return this.get<StoredFile>( `/projects/${projectId}/storage/metadata/${fileId}` ); } async deleteFile( projectId: string, fileId: string ): Promise<ApiResponse<{ success: boolean }>> { return this.delete<{ success: boolean }>( `/projects/${projectId}/storage/files/${fileId}` ); } async getFiles( projectId: string, options?: FileFilter & { limit?: number; offset?: number; sort_by?: string; sort_order?: "asc" | "desc"; } ): Promise<PaginatedResponse<StoredFile>> { const params = new URLSearchParams(); if (options?.folder_id) params.append("folder_id", options.folder_id); if (options?.mime_type) params.append("mime_type", options.mime_type); if (options?.file_extension) params.append("file_extension", options.file_extension); if (options?.tags) params.append("tags", JSON.stringify(options.tags)); if (options?.uploaded_by) params.append("uploaded_by", options.uploaded_by); if (options?.is_public !== undefined) params.append("is_public", options.is_public.toString()); if (options?.created_after) params.append("created_after", options.created_after); if (options?.created_before) params.append("created_before", options.created_before); if (options?.limit) params.append("limit", options.limit.toString()); if (options?.offset) params.append("offset", options.offset.toString()); if (options?.sort_by) params.append("sort_by", options.sort_by); if (options?.sort_order) params.append("sort_order", options.sort_order); const queryParams: Record<string, string> = {}; params.forEach((value, key) => { queryParams[key] = value; }); return this.getPaginated<StoredFile>( `/projects/${projectId}/storage/files`, queryParams ); } // Folder Management async createFolder( projectId: string, folderData: { name: string; parent_id?: string; description?: string; is_public?: boolean; metadata?: Record<string, unknown>; } ): Promise<ApiResponse<FileFolder>> { return this.post<FileFolder>( `/projects/${projectId}/storage/folders`, folderData ); } async getFolders( projectId: string, parentFolderId?: string ): Promise<ApiResponse<FileFolder[]>> { const url = parentFolderId ? `/projects/${projectId}/storage/folders?parent_id=${parentFolderId}` : `/projects/${projectId}/storage/folders`; return this.get<FileFolder[]>(url); } async updateFolder( projectId: string, folderId: string, updates: Partial<FileFolder> ): Promise<ApiResponse<FileFolder>> { return this.put<FileFolder>( `/projects/${projectId}/storage/folders/${folderId}`, updates ); } async deleteFolder( projectId: string, folderId: string ): Promise<ApiResponse<{ success: boolean }>> { return this.delete<{ success: boolean }>( `/projects/${projectId}/storage/folders/${folderId}` ); } // File Operations async copyFile( projectId: string, fileId: string, destination: { folder_id?: string; new_name?: string; } ): Promise<ApiResponse<StoredFile>> { return this.post<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/copy`, destination ); } async moveFile( projectId: string, fileId: string, destination: { folder_id?: string; new_name?: string; } ): Promise<ApiResponse<StoredFile>> { return this.put<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/move`, destination ); } async renameFile( projectId: string, fileId: string, newName: string ): Promise<ApiResponse<StoredFile>> { return this.put<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/rename`, { new_name: newName } ); } // File Metadata async updateFileMetadata( projectId: string, fileId: string, metadata: Record<string, unknown> ): Promise<ApiResponse<StoredFile>> { return this.put<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/metadata`, { metadata } ); } async addFileTags( projectId: string, fileId: string, tags: string[] ): Promise<ApiResponse<StoredFile>> { return this.post<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/tags`, { tags } ); } async removeFileTags( projectId: string, fileId: string, tags: string[] ): Promise<ApiResponse<StoredFile>> { return this.delete<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/tags`, { tags } ); } // File Access async getFileUrl( projectId: string, fileId: string, options?: FileUrlRequest ): Promise<ApiResponse<{ url: string; expires_at?: string }>> { const params = new URLSearchParams(); if (options?.expires_in) params.append("expires_in", options.expires_in.toString()); if (options?.access_type) params.append("access_type", options.access_type); const url = params.toString() ? `/projects/${projectId}/storage/files/${fileId}/url?${params}` : `/projects/${projectId}/storage/files/${fileId}/url`; return this.get<{ url: string; expires_at?: string }>(url); } async makeFilePublic( projectId: string, fileId: string ): Promise<ApiResponse<StoredFile>> { return this.put<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/public`, { is_public: true } ); } async makeFilePrivate( projectId: string, fileId: string ): Promise<ApiResponse<StoredFile>> { return this.put<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/public`, { is_public: false } ); } // File Permissions async getFilePermissions( projectId: string, fileId: string ): Promise<ApiResponse<FilePermission[]>> { return this.get<FilePermission[]>( `/projects/${projectId}/storage/files/${fileId}/permissions` ); } async grantFilePermission( projectId: string, fileId: string, permission: { user_id?: string; role?: string; permission_type: "read" | "write" | "delete" | "admin"; expires_at?: string; } ): Promise<ApiResponse<FilePermission>> { return this.post<FilePermission>( `/projects/${projectId}/storage/files/${fileId}/permissions`, permission ); } async revokeFilePermission( projectId: string, fileId: string, permissionId: string ): Promise<ApiResponse<{ success: boolean }>> { return this.delete<{ success: boolean }>( `/projects/${projectId}/storage/files/${fileId}/permissions/${permissionId}` ); } // File Versions async getFileVersions( projectId: string, fileId: string ): Promise<ApiResponse<FileVersion[]>> { return this.get<FileVersion[]>( `/projects/${projectId}/storage/files/${fileId}/versions` ); } async uploadFileVersion( projectId: string, fileId: string, file: File ): Promise<ApiResponse<FileVersion>> { const formData = new FormData(); formData.append("file", file); return this.post<FileVersion>( `/projects/${projectId}/storage/files/${fileId}/versions`, formData ); } async restoreFileVersion( projectId: string, fileId: string, versionId: string ): Promise<ApiResponse<StoredFile>> { return this.post<StoredFile>( `/projects/${projectId}/storage/files/${fileId}/versions/${versionId}/restore` ); } // Storage Analytics async getStorageStatistics( projectId: string ): Promise<ApiResponse<StorageStatistics>> { return this.get<StorageStatistics>( `/projects/${projectId}/storage/statistics` ); } async getStorageQuota(projectId: string): Promise< ApiResponse<{ used: number; limit: number; percentage: number; }> > { return this.get<{ used: number; limit: number; percentage: number; }>(`/projects/${projectId}/storage/quota`); } // Bulk Operations async bulkDeleteFiles( projectId: string, fileIds: string[] ): Promise<ApiResponse<{ success: boolean; deleted_count: number }>> { return this.post<{ success: boolean; deleted_count: number }>( `/projects/${projectId}/storage/bulk-delete`, { file_ids: fileIds } ); } async bulkMoveFiles( projectId: string, fileIds: string[], destination: { folder_id?: string; } ): Promise<ApiResponse<{ success: boolean; moved_count: number }>> { return this.post<{ success: boolean; moved_count: number }>( `/projects/${projectId}/storage/bulk-move`, { file_ids: fileIds, destination, } ); } async bulkUpdateMetadata( projectId: string, fileIds: string[], metadata: Record<string, unknown> ): Promise<ApiResponse<{ success: boolean; updated_count: number }>> { return this.post<{ success: boolean; updated_count: number }>( `/projects/${projectId}/storage/bulk-update-metadata`, { file_ids: fileIds, metadata, } ); } }