Spaces:
Sleeping
Sleeping
Download dist/utils/fileSystem.js from sardarbipul/test: direct link, hf CLI and curl.
- Browser
- Download file 8.08 kB
-
https://huggingface.co/spaces/sardarbipul/test/resolve/main/dist/utils/fileSystem.js
- Command line
-
hf download hf://spaces/sardarbipul/test/dist/utils/fileSystem.js
-
curl -L -o fileSystem.js https://huggingface.co/spaces/sardarbipul/test/resolve/main/dist/utils/fileSystem.js
8.08 kB
| ; | |
| var __importDefault = (this && this.__importDefault) || function (mod) { | |
| return (mod && mod.__esModule) ? mod : { "default": mod }; | |
| }; | |
| Object.defineProperty(exports, "__esModule", { value: true }); | |
| exports.DATA_ROOT = void 0; | |
| exports.ensureDataRootExists = ensureDataRootExists; | |
| exports.formatBytes = formatBytes; | |
| exports.safeResolvePath = safeResolvePath; | |
| exports.getBreadcrumbs = getBreadcrumbs; | |
| exports.listDirectory = listDirectory; | |
| exports.getFileDetails = getFileDetails; | |
| const fs_1 = __importDefault(require("fs")); | |
| const path_1 = __importDefault(require("path")); | |
| const mime_types_1 = __importDefault(require("mime-types")); | |
| // Storage root directory: defaults to /data on HuggingFace Space | |
| // Can be customized via DATA_DIR env var (e.g. for local testing) | |
| const DEFAULT_DATA_DIR = process.platform === 'win32' ? path_1.default.resolve(process.cwd(), 'data_local') : '/data'; | |
| exports.DATA_ROOT = path_1.default.resolve(process.env.DATA_DIR || DEFAULT_DATA_DIR); | |
| // Ensure root storage directory exists in local/dev environment | |
| function ensureDataRootExists() { | |
| if (!fs_1.default.existsSync(exports.DATA_ROOT)) { | |
| try { | |
| fs_1.default.mkdirSync(exports.DATA_ROOT, { recursive: true }); | |
| console.log(`[Storage] Created storage directory at: ${exports.DATA_ROOT}`); | |
| } | |
| catch (err) { | |
| console.error(`[Storage Error] Could not create storage root ${exports.DATA_ROOT}:`, err); | |
| } | |
| } | |
| return exports.DATA_ROOT; | |
| } | |
| function formatBytes(bytes, decimals = 2) { | |
| if (bytes === 0) | |
| return '0 Bytes'; | |
| const k = 1024; | |
| const dm = decimals < 0 ? 0 : decimals; | |
| const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; | |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; | |
| } | |
| function safeResolvePath(subPath = '') { | |
| ensureDataRootExists(); | |
| // Normalize and remove leading slashes | |
| const cleanSubPath = path_1.default.normalize(subPath).replace(/^(\.\.[\/\\])+/, '').replace(/^[/\\]+/, ''); | |
| const fullPath = path_1.default.resolve(exports.DATA_ROOT, cleanSubPath); | |
| // Security check: path traversal prevention | |
| if (!fullPath.startsWith(exports.DATA_ROOT)) { | |
| throw new Error('Access denied: Invalid path traversal target.'); | |
| } | |
| const relativePath = path_1.default.relative(exports.DATA_ROOT, fullPath).replace(/\\/g, '/'); | |
| return { fullPath, relativePath }; | |
| } | |
| function getBreadcrumbs(relativePath) { | |
| const parts = relativePath.split('/').filter(Boolean); | |
| const crumbs = [{ name: 'data', path: '' }]; | |
| let accumulated = ''; | |
| for (const part of parts) { | |
| accumulated = accumulated ? `${accumulated}/${part}` : part; | |
| crumbs.push({ name: part, path: accumulated }); | |
| } | |
| return crumbs; | |
| } | |
| function getCategory(isDirectory, ext, mimeType) { | |
| if (isDirectory) | |
| return 'folder'; | |
| ext = ext.toLowerCase(); | |
| if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico'].includes(ext)) | |
| return 'image'; | |
| if (['txt', 'md', 'json', 'js', 'ts', 'html', 'css', 'py', 'sh', 'yaml', 'yml', 'xml', 'c', 'cpp', 'rs', 'go', 'java'].includes(ext)) | |
| return 'code'; | |
| if (['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(ext)) | |
| return 'document'; | |
| if (['mp3', 'wav', 'ogg', 'flac', 'm4a'].includes(ext)) | |
| return 'audio'; | |
| if (['mp4', 'webm', 'mkv', 'avi', 'mov'].includes(ext)) | |
| return 'video'; | |
| if (['zip', 'tar', 'gz', 'bz2', '7z', 'rar'].includes(ext)) | |
| return 'archive'; | |
| if (['csv', 'parquet', 'arrow', 'feather', 'h5', 'hdf5', 'npy', 'npz', 'pt', 'pth', 'bin', 'onnx', 'safetensors'].includes(ext)) | |
| return 'data'; | |
| return 'file'; | |
| } | |
| function listDirectory(subPath = '') { | |
| const { fullPath, relativePath } = safeResolvePath(subPath); | |
| if (!fs_1.default.existsSync(fullPath)) { | |
| throw new Error(`Directory does not exist: /data/${relativePath}`); | |
| } | |
| const stat = fs_1.default.statSync(fullPath); | |
| if (!stat.isDirectory()) { | |
| throw new Error(`Path /data/${relativePath} is a file, not a directory.`); | |
| } | |
| const filenames = fs_1.default.readdirSync(fullPath); | |
| const items = []; | |
| let totalFiles = 0; | |
| let totalFolders = 0; | |
| let totalSize = 0; | |
| for (const name of filenames) { | |
| try { | |
| const itemFullPath = path_1.default.join(fullPath, name); | |
| const itemStat = fs_1.default.statSync(itemFullPath); | |
| const isDir = itemStat.isDirectory(); | |
| const ext = isDir ? '' : path_1.default.extname(name).slice(1); | |
| const mimeType = isDir ? '' : (mime_types_1.default.lookup(name) || 'application/octet-stream'); | |
| const itemRelPath = relativePath ? `${relativePath}/${name}` : name; | |
| const size = isDir ? 0 : itemStat.size; | |
| if (isDir) { | |
| totalFolders++; | |
| } | |
| else { | |
| totalFiles++; | |
| totalSize += size; | |
| } | |
| items.push({ | |
| name, | |
| relativePath: itemRelPath, | |
| isDirectory: isDir, | |
| size, | |
| formattedSize: isDir ? '--' : formatBytes(size), | |
| modifiedAt: itemStat.mtime, | |
| extension: ext, | |
| mimeType, | |
| category: getCategory(isDir, ext, mimeType), | |
| }); | |
| } | |
| catch (e) { | |
| console.warn(`Could not stat item ${name} in ${fullPath}`, e); | |
| } | |
| } | |
| // Sort folders first, then files alphabetically | |
| items.sort((a, b) => { | |
| if (a.isDirectory && !b.isDirectory) | |
| return -1; | |
| if (!a.isDirectory && b.isDirectory) | |
| return 1; | |
| return a.name.localeCompare(b.name, undefined, { sensitivity: 'base', numeric: true }); | |
| }); | |
| return { | |
| items, | |
| relativePath, | |
| breadcrumbs: getBreadcrumbs(relativePath), | |
| totalFiles, | |
| totalFolders, | |
| totalSize, | |
| }; | |
| } | |
| function getFileDetails(subPath) { | |
| const { fullPath, relativePath } = safeResolvePath(subPath); | |
| if (!fs_1.default.existsSync(fullPath)) { | |
| throw new Error(`File does not exist: /data/${relativePath}`); | |
| } | |
| const stat = fs_1.default.statSync(fullPath); | |
| if (stat.isDirectory()) { | |
| throw new Error(`Path is a directory, not a file.`); | |
| } | |
| const name = path_1.default.basename(fullPath); | |
| const ext = path_1.default.extname(name).slice(1).toLowerCase(); | |
| const mimeType = mime_types_1.default.lookup(name) || 'application/octet-stream'; | |
| const category = getCategory(false, ext, mimeType); | |
| let textContent = null; | |
| const MAX_PREVIEW_SIZE = 1024 * 1024; // 1 MB limit for text preview | |
| if (category === 'code' || ['csv', 'txt', 'json', 'md', 'log', 'yaml', 'yml'].includes(ext)) { | |
| if (stat.size <= MAX_PREVIEW_SIZE) { | |
| try { | |
| textContent = fs_1.default.readFileSync(fullPath, 'utf-8'); | |
| } | |
| catch (err) { | |
| textContent = `[Unable to read text content: ${err}]`; | |
| } | |
| } | |
| else { | |
| // Read first 50KB for large files | |
| try { | |
| const fd = fs_1.default.openSync(fullPath, 'r'); | |
| const buffer = Buffer.alloc(50 * 1024); | |
| const bytesRead = fs_1.default.readSync(fd, buffer, 0, buffer.length, 0); | |
| fs_1.default.closeSync(fd); | |
| textContent = buffer.toString('utf-8', 0, bytesRead) + `\n\n... [Preview truncated. Total size: ${formatBytes(stat.size)}]`; | |
| } | |
| catch (err) { | |
| textContent = `[Error reading partial preview]`; | |
| } | |
| } | |
| } | |
| return { | |
| name, | |
| relativePath, | |
| fullPath, | |
| size: stat.size, | |
| formattedSize: formatBytes(stat.size), | |
| modifiedAt: stat.mtime, | |
| extension: ext, | |
| mimeType, | |
| category, | |
| textContent, | |
| breadcrumbs: getBreadcrumbs(relativePath), | |
| }; | |
| } | |