From 9c582e1a43b9aa30e7048cd3ea6a3ce916c76c87 Mon Sep 17 00:00:00 2001 From: BOHA Date: Sat, 6 Jun 2026 02:33:40 +0200 Subject: [PATCH] fix(nas): log swallowed filesystem errors instead of silently dropping them nas-file-manager (21) and nas-financials-manager (9) had empty catch blocks that swallowed mkdir/write/rm/rename/stat/readdir failures with zero logging, making NAS issues undebuggable (violates the 'never silently swallow errors' rule). Added a contextual console.error to each real-failure catch (matching the existing service console.* pattern); control flow and return values unchanged. Left 3 ENOENT-as-expected catches (move/createFolder existence checks, symlink-traversal guard) as deliberate no-logs. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/services/nas-file-manager.ts | 118 ++++++++++++++++++++----- src/services/nas-financials-manager.ts | 64 +++++++++++--- 2 files changed, 150 insertions(+), 32 deletions(-) diff --git a/src/services/nas-file-manager.ts b/src/services/nas-file-manager.ts index b99bbf0..1bcf69a 100644 --- a/src/services/nas-file-manager.ts +++ b/src/services/nas-file-manager.ts @@ -115,7 +115,12 @@ export class NasFileManager { return ( fs.existsSync(this.basePath) && fs.statSync(this.basePath).isDirectory() ); - } catch { + } catch (err) { + console.error( + "[nas-file-manager] stat failed for basePath:", + this.basePath, + err, + ); return false; } } @@ -136,7 +141,8 @@ export class NasFileManager { try { fs.mkdirSync(fullPath, { recursive: true, mode: 0o775 }); return true; - } catch { + } catch (err) { + console.error("[nas-file-manager] mkdir failed for path:", fullPath, err); return false; } } @@ -150,7 +156,12 @@ export class NasFileManager { try { await fs.promises.rm(folderPath, { recursive: true, force: true }); return true; - } catch { + } catch (err) { + console.error( + "[nas-file-manager] delete failed for path:", + folderPath, + err, + ); return false; } } @@ -173,7 +184,14 @@ export class NasFileManager { try { fs.renameSync(currentPath, newPath); return true; - } catch { + } catch (err) { + console.error( + "[nas-file-manager] rename failed:", + currentPath, + "→", + newPath, + err, + ); return false; } } @@ -188,14 +206,20 @@ export class NasFileManager { try { const stat = fs.lstatSync(dirPath); if (!stat.isDirectory()) return null; - } catch { + } catch (err) { + console.error("[nas-file-manager] lstat failed for path:", dirPath, err); return null; } let entries: string[]; try { entries = fs.readdirSync(dirPath); - } catch { + } catch (err) { + console.error( + "[nas-file-manager] readdir failed for path:", + dirPath, + err, + ); return null; } @@ -206,7 +230,12 @@ export class NasFileManager { let lstat: fs.Stats; try { lstat = fs.lstatSync(fullPath); - } catch { + } catch (err) { + console.error( + "[nas-file-manager] lstat failed for entry:", + fullPath, + err, + ); continue; } @@ -216,7 +245,12 @@ export class NasFileManager { if (isLink) { try { isDir = fs.statSync(fullPath).isDirectory(); - } catch { + } catch (err) { + console.error( + "[nas-file-manager] stat failed for symlink target:", + fullPath, + err, + ); isDir = false; } } else { @@ -237,8 +271,12 @@ export class NasFileManager { try { const target = fs.readlinkSync(fullPath); item.link_target = target; - } catch { - // ignore + } catch (err) { + console.error( + "[nas-file-manager] readlink failed for:", + fullPath, + err, + ); } } @@ -279,7 +317,12 @@ export class NasFileManager { let realDirPath: string; try { realDirPath = fs.realpathSync(dirPath); - } catch { + } catch (err) { + console.error( + "[nas-file-manager] realpath failed for path:", + dirPath, + err, + ); realDirPath = dirPath; } @@ -304,14 +347,16 @@ export class NasFileManager { try { await fs.promises.mkdir(dirPath, { recursive: true, mode: 0o775 }); - } catch { + } catch (err) { + console.error("[nas-file-manager] mkdir failed for path:", dirPath, err); return "Cílová složka neexistuje"; } let stat: fs.Stats; try { stat = await fs.promises.stat(dirPath); - } catch { + } catch (err) { + console.error("[nas-file-manager] stat failed for path:", dirPath, err); return "Cílová složka neexistuje"; } if (!stat.isDirectory()) { @@ -376,7 +421,8 @@ export class NasFileManager { try { const stat = fs.lstatSync(fullPath); if (!stat.isFile()) return null; - } catch { + } catch (err) { + console.error("[nas-file-manager] lstat failed for path:", fullPath, err); return null; } @@ -413,7 +459,8 @@ export class NasFileManager { try { const stat = await fs.promises.lstat(fullPath); isDir = stat.isDirectory(); - } catch { + } catch (err) { + console.error("[nas-file-manager] lstat failed for path:", fullPath, err); return "Soubor nebo složka neexistuje"; } @@ -423,7 +470,12 @@ export class NasFileManager { } else { await fs.promises.unlink(fullPath); } - } catch { + } catch (err) { + console.error( + "[nas-file-manager] delete failed for path:", + fullPath, + err, + ); return isDir ? "Nepodařilo se smazat složku" : "Nepodařilo se smazat soubor"; @@ -455,7 +507,12 @@ export class NasFileManager { try { await fs.promises.stat(fullFrom); - } catch { + } catch (err) { + console.error( + "[nas-file-manager] stat failed for source path:", + fullFrom, + err, + ); return "Zdrojový soubor neexistuje"; } @@ -509,7 +566,8 @@ export class NasFileManager { if (stat.isSymbolicLink() || !stat.isDirectory()) { return "Nadřazená složka neexistuje"; } - } catch { + } catch (err) { + console.error("[nas-file-manager] lstat failed for path:", dirPath, err); return "Nadřazená složka neexistuje"; } @@ -528,7 +586,8 @@ export class NasFileManager { try { await fs.promises.mkdir(newPath, { mode: 0o775 }); - } catch { + } catch (err) { + console.error("[nas-file-manager] mkdir failed for path:", newPath, err); return "Nepodařilo se vytvořit složku"; } @@ -559,7 +618,12 @@ export class NasFileManager { let entries: string[]; try { entries = fs.readdirSync(this.basePath); - } catch { + } catch (err) { + console.error( + "[nas-file-manager] readdir failed for basePath:", + this.basePath, + err, + ); return null; } @@ -571,7 +635,12 @@ export class NasFileManager { if (fs.statSync(fullPath).isDirectory()) { return fullPath; } - } catch { + } catch (err) { + console.error( + "[nas-file-manager] stat failed for entry:", + fullPath, + err, + ); continue; } } @@ -676,7 +745,12 @@ export class NasFileManager { try { const entries = fs.readdirSync(dirPath); return entries.length; - } catch { + } catch (err) { + console.error( + "[nas-file-manager] readdir failed for path:", + dirPath, + err, + ); return 0; } } diff --git a/src/services/nas-financials-manager.ts b/src/services/nas-financials-manager.ts index c55bee8..3d64c91 100644 --- a/src/services/nas-financials-manager.ts +++ b/src/services/nas-financials-manager.ts @@ -23,7 +23,12 @@ class NasFinancialsManager { try { fs.mkdirSync(this.basePath, { recursive: true }); return fs.statSync(this.basePath).isDirectory(); - } catch { + } catch (err) { + console.error( + "[nas-financials-manager] mkdir/stat failed for basePath:", + this.basePath, + err, + ); return false; } } @@ -44,7 +49,12 @@ class NasFinancialsManager { const monthPath = path.join(yearPath, monthDir); try { if (!fs.statSync(monthPath).isDirectory()) continue; - } catch { + } catch (err) { + console.error( + "[nas-financials-manager] stat failed for monthPath:", + monthPath, + err, + ); continue; } const filePath = path.join(monthPath, safeName); @@ -53,8 +63,12 @@ class NasFinancialsManager { } } } - } catch { - // best effort + } catch (err) { + console.error( + "[nas-financials-manager] cleanIssuedInvoice failed for:", + invoiceNumber, + err, + ); } } @@ -73,7 +87,12 @@ class NasFinancialsManager { try { fs.writeFileSync(fullPath, pdfBuffer); return `${DIR_ISSUED}/${year}/${this.pad(month)}/${path.basename(fullPath)}`; - } catch { + } catch (err) { + console.error( + "[nas-financials-manager] write failed for issued invoice:", + fullPath, + err, + ); return null; } } @@ -86,7 +105,12 @@ class NasFinancialsManager { try { const data = fs.readFileSync(fullPath); return { data, fileName: path.basename(fullPath) }; - } catch { + } catch (err) { + console.error( + "[nas-financials-manager] read failed for issued invoice:", + fullPath, + err, + ); return null; } } @@ -97,7 +121,12 @@ class NasFinancialsManager { try { fs.unlinkSync(fullPath); return true; - } catch { + } catch (err) { + console.error( + "[nas-financials-manager] delete failed for issued invoice:", + fullPath, + err, + ); return false; } } @@ -148,7 +177,12 @@ class NasFinancialsManager { try { const data = fs.readFileSync(fullPath); return { data, fileName: path.basename(fullPath) }; - } catch { + } catch (err) { + console.error( + "[nas-financials-manager] read failed for received invoice:", + fullPath, + err, + ); return null; } } @@ -160,7 +194,12 @@ class NasFinancialsManager { try { fs.unlinkSync(fullPath); return true; - } catch { + } catch (err) { + console.error( + "[nas-financials-manager] delete failed for received invoice:", + fullPath, + err, + ); return false; } } @@ -181,7 +220,12 @@ class NasFinancialsManager { try { fs.mkdirSync(dirPath, { recursive: true }); return dirPath; - } catch { + } catch (err) { + console.error( + "[nas-financials-manager] mkdir failed for path:", + dirPath, + err, + ); return null; } }