"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getStorageRoot = getStorageRoot; exports.getPublicStorageRoot = getPublicStorageRoot; exports.getPrivateStorageRoot = getPrivateStorageRoot; exports.getLegacyStorageRoots = getLegacyStorageRoots; exports.assertStorageConfiguration = assertStorageConfiguration; exports.getProtectedCustomerLicenseImageUrl = getProtectedCustomerLicenseImageUrl; exports.uploadImage = uploadImage; exports.resolveStoredFilePath = resolveStoredFilePath; exports.deleteImage = deleteImage; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const crypto_1 = __importDefault(require("crypto")); const APP_PACKAGE_ROOT = path_1.default.resolve(__dirname, '..', '..', '..'); const APP_SOURCE_ROOT = path_1.default.join(APP_PACKAGE_ROOT, 'src'); const APP_DIST_ROOT = path_1.default.join(APP_PACKAGE_ROOT, 'dist'); const DEFAULT_STORAGE_ROOT = path_1.default.join(APP_PACKAGE_ROOT, 'storage'); const LEGACY_STORAGE_ROOTS = [ path_1.default.join(APP_SOURCE_ROOT, 'lib', 'storage'), ]; function getStorageRoot() { return process.env.FILE_STORAGE_ROOT ? path_1.default.resolve(process.env.FILE_STORAGE_ROOT) : DEFAULT_STORAGE_ROOT; } function getPublicStorageRoot() { return path_1.default.join(getStorageRoot(), 'public'); } function getPrivateStorageRoot() { return path_1.default.join(getStorageRoot(), 'private'); } function getLegacyStorageRoots() { return LEGACY_STORAGE_ROOTS; } function isWithinPath(targetPath, parentPath) { const relative = path_1.default.relative(parentPath, targetPath); return relative === '' || (!relative.startsWith('..') && !path_1.default.isAbsolute(relative)); } function assertStorageConfiguration() { const storageRoot = getStorageRoot(); if (process.env.NODE_ENV === 'production' && !process.env.FILE_STORAGE_ROOT) { throw new Error('FILE_STORAGE_ROOT must be set in production so uploads are stored on the mounted volume.'); } if (process.env.NODE_ENV === 'production') { const forbiddenRoots = [APP_PACKAGE_ROOT, APP_SOURCE_ROOT, APP_DIST_ROOT]; const invalidRoot = forbiddenRoots.find((root) => isWithinPath(storageRoot, root)); if (invalidRoot) { throw new Error(`FILE_STORAGE_ROOT must point outside the API app tree in production. Received ${storageRoot}, which is inside ${invalidRoot}.`); } } return storageRoot; } function ensureStorageRoot(visibility) { assertStorageConfiguration(); const root = visibility === 'public' ? getPublicStorageRoot() : getPrivateStorageRoot(); fs_1.default.mkdirSync(root, { recursive: true }); return root; } function inferVisibility(folder) { const normalized = folder.replace(/\\/g, '/'); if (/\/customers\//.test(`/${normalized}/`)) return 'private'; if (/\/licenses?\//.test(`/${normalized}/`)) return 'private'; if (/\/contracts?\//.test(`/${normalized}/`)) return 'private'; if (/\/documents?\//.test(`/${normalized}/`)) return 'private'; if (/\/inspections?\//.test(`/${normalized}/`)) return 'private'; if (/\/internal\//.test(`/${normalized}/`)) return 'private'; return 'public'; } function getApiBase() { return (process.env.API_URL ?? 'http://localhost:4000').replace(/\/$/, ''); } function getDashboardBase() { return (process.env.DASHBOARD_URL ?? process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard').replace(/\/$/, ''); } function getStorageRelativePath(imageUrl) { const marker = '/storage/'; const idx = imageUrl.indexOf(marker); if (idx === -1) return null; return imageUrl.slice(idx + marker.length); } function getProtectedCustomerLicenseImageUrl(customerId) { return `${getDashboardBase()}/api/v1/customers/${customerId}/license-image`; } async function uploadImage(buffer, folder, publicId, visibility = inferVisibility(folder)) { const storageRoot = ensureStorageRoot(visibility); const folderPath = path_1.default.join(storageRoot, folder); if (!isWithinPath(folderPath, storageRoot)) { throw new Error('Upload path escapes storage root'); } fs_1.default.mkdirSync(folderPath, { recursive: true }); const filename = publicId ? `${publicId}.jpg` : `${crypto_1.default.randomBytes(16).toString('hex')}.jpg`; fs_1.default.writeFileSync(path_1.default.join(folderPath, filename), buffer); return `${getApiBase()}/storage/${folder}/${filename}`; } function resolveStoredFilePath(imageUrl) { const relative = getStorageRelativePath(imageUrl); if (!relative) return null; const roots = [getPublicStorageRoot(), getPrivateStorageRoot(), ...getLegacyStorageRoots(), assertStorageConfiguration()]; for (const root of roots) { const filePath = path_1.default.join(root, relative); if (!isWithinPath(filePath, root)) continue; if (fs_1.default.existsSync(filePath)) { return filePath; } } return null; } async function deleteImage(imageUrl) { const filePath = resolveStoredFilePath(imageUrl); if (filePath && fs_1.default.existsSync(filePath)) { fs_1.default.unlinkSync(filePath); } } //# sourceMappingURL=storage.js.map