Files
demat-facturation/server/localStorage.ts

112 lines
3.1 KiB
TypeScript

import fs from "fs/promises";
import path from "path";
import { nanoid } from "nanoid";
// Storage base path (local filesystem)
const STORAGE_BASE_PATH = process.env.STORAGE_BASE_PATH || path.join(process.cwd(), "storage");
/**
* Ensure storage directory exists
*/
async function ensureStorageDir(dirPath: string) {
try {
await fs.mkdir(dirPath, { recursive: true });
} catch (error) {
console.error(`[LocalStorage] Failed to create directory ${dirPath}:`, error);
throw error;
}
}
/**
* Generate a storage key with YYYY-MM prefix for organization
*/
export function generateStorageKey(userId: number, fileName: string): string {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, "0");
const randomId = nanoid(8);
// Format: YYYY-MM/userId-randomId-filename
return `${year}-${month}/${userId}-${randomId}-${fileName}`;
}
/**
* Store a file in local storage
* @param fileKey - Storage key (e.g., "2025-01/1-abc123-invoice.pdf")
* @param buffer - File content as Buffer
* @param contentType - MIME type (optional, for metadata)
* @returns Object with key and public URL
*/
export async function localStoragePut(
fileKey: string,
buffer: Buffer,
_contentType?: string
): Promise<{ key: string; url: string }> {
try {
const fullPath = path.join(STORAGE_BASE_PATH, fileKey);
const dirPath = path.dirname(fullPath);
// Ensure directory exists
await ensureStorageDir(dirPath);
// Write file
await fs.writeFile(fullPath, buffer);
// Generate public URL (served by Express static middleware)
const url = `/storage/${fileKey}`;
console.log(`[LocalStorage] File stored: ${fileKey}`);
return { key: fileKey, url };
} catch (error) {
console.error(`[LocalStorage] Failed to store file ${fileKey}:`, error);
throw error;
}
}
/**
* Retrieve a file from local storage
* @param fileKey - Storage key
* @returns File content as Buffer
*/
export async function localStorageGet(fileKey: string): Promise<Buffer> {
try {
const fullPath = path.join(STORAGE_BASE_PATH, fileKey);
const buffer = await fs.readFile(fullPath);
return buffer;
} catch (error) {
console.error(`[LocalStorage] Failed to retrieve file ${fileKey}:`, error);
throw error;
}
}
/**
* Delete a file from local storage
* @param fileKey - Storage key
*/
export async function localStorageDelete(fileKey: string): Promise<void> {
try {
const fullPath = path.join(STORAGE_BASE_PATH, fileKey);
await fs.unlink(fullPath);
console.log(`[LocalStorage] File deleted: ${fileKey}`);
} catch (error) {
console.error(`[LocalStorage] Failed to delete file ${fileKey}:`, error);
throw error;
}
}
/**
* Check if a file exists in storage
* @param fileKey - Storage key
* @returns true if file exists, false otherwise
*/
export async function localStorageExists(fileKey: string): Promise<boolean> {
try {
const fullPath = path.join(STORAGE_BASE_PATH, fileKey);
await fs.access(fullPath);
return true;
} catch {
return false;
}
}