Skip to content

Commit e947e8b

Browse files
committed
perf(fs): add lazy caching for allowed directories in safeDelete
Cache resolved allowed directories (tmpdir, cacache, socketUserDir) on first safeDelete call to avoid re-computing them on every invocation. These paths don't change during process lifetime, so caching provides significant performance improvement when safeDelete is called frequently. Benefits: - Avoids loading os, path, and paths modules repeatedly - Skips calling os.tmpdir(), getSocketCacacheDir(), getSocketUserDir() - Eliminates path.resolve() calls for all 3 directories - Applied to both safeDelete() and safeDeleteSync() This is especially beneficial in cleanup operations that process multiple files, such as cleanupIpcStubs() which calls safeDelete in a Promise.all() loop.
1 parent f42cf5f commit e947e8b

File tree

1 file changed

+36
-36
lines changed

1 file changed

+36
-36
lines changed

src/fs.ts

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,38 @@ export function readJsonSync(
10741074
})
10751075
}
10761076

1077+
// Lazy cache for allowed directories to avoid re-resolving on every safeDelete call
1078+
let _cachedAllowedDirs: string[] | undefined
1079+
1080+
/**
1081+
* Get allowed directories for safe deletion with lazy caching.
1082+
* These directories don't change during process lifetime, so we cache them.
1083+
*/
1084+
function getAllowedDirectories(): string[] {
1085+
if (_cachedAllowedDirs === undefined) {
1086+
const os = getOs()
1087+
const path = getPath()
1088+
const {
1089+
getSocketCacacheDir,
1090+
getSocketUserDir,
1091+
} = /*@__PURE__*/ require('#lib/paths')
1092+
1093+
const tmpDir = os.tmpdir()
1094+
const resolvedTmpDir = path.resolve(tmpDir)
1095+
const cacacheDir = getSocketCacacheDir()
1096+
const resolvedCacacheDir = path.resolve(cacacheDir)
1097+
const socketUserDir = getSocketUserDir()
1098+
const resolvedSocketUserDir = path.resolve(socketUserDir)
1099+
1100+
_cachedAllowedDirs = [
1101+
resolvedTmpDir,
1102+
resolvedCacacheDir,
1103+
resolvedSocketUserDir,
1104+
]
1105+
}
1106+
return _cachedAllowedDirs
1107+
}
1108+
10771109
/**
10781110
* Safely delete a file or directory asynchronously with built-in protections.
10791111
* Uses `del` for safer deletion that prevents removing cwd and above by default.
@@ -1113,31 +1145,15 @@ export async function safeDelete(
11131145
// Check if we're deleting within allowed directories.
11141146
let shouldForce = opts.force !== false
11151147
if (!shouldForce && patterns.length > 0) {
1116-
const os = getOs()
11171148
const path = getPath()
1118-
const {
1119-
getSocketCacacheDir,
1120-
getSocketUserDir,
1121-
} = /*@__PURE__*/ require('#lib/paths')
1122-
1123-
// Get allowed directories
1124-
const tmpDir = os.tmpdir()
1125-
const resolvedTmpDir = path.resolve(tmpDir)
1126-
const cacacheDir = getSocketCacacheDir()
1127-
const resolvedCacacheDir = path.resolve(cacacheDir)
1128-
const socketUserDir = getSocketUserDir()
1129-
const resolvedSocketUserDir = path.resolve(socketUserDir)
1149+
const allowedDirs = getAllowedDirectories()
11301150

11311151
// Check if all patterns are within allowed directories.
11321152
const allInAllowedDirs = patterns.every(pattern => {
11331153
const resolvedPath = path.resolve(pattern)
11341154

11351155
// Check each allowed directory
1136-
for (const allowedDir of [
1137-
resolvedTmpDir,
1138-
resolvedCacacheDir,
1139-
resolvedSocketUserDir,
1140-
]) {
1156+
for (const allowedDir of allowedDirs) {
11411157
const isInAllowedDir =
11421158
resolvedPath.startsWith(allowedDir + path.sep) ||
11431159
resolvedPath === allowedDir
@@ -1204,31 +1220,15 @@ export function safeDeleteSync(
12041220
// Check if we're deleting within allowed directories.
12051221
let shouldForce = opts.force !== false
12061222
if (!shouldForce && patterns.length > 0) {
1207-
const os = getOs()
12081223
const path = getPath()
1209-
const {
1210-
getSocketCacacheDir,
1211-
getSocketUserDir,
1212-
} = /*@__PURE__*/ require('#lib/paths')
1213-
1214-
// Get allowed directories
1215-
const tmpDir = os.tmpdir()
1216-
const resolvedTmpDir = path.resolve(tmpDir)
1217-
const cacacheDir = getSocketCacacheDir()
1218-
const resolvedCacacheDir = path.resolve(cacacheDir)
1219-
const socketUserDir = getSocketUserDir()
1220-
const resolvedSocketUserDir = path.resolve(socketUserDir)
1224+
const allowedDirs = getAllowedDirectories()
12211225

12221226
// Check if all patterns are within allowed directories.
12231227
const allInAllowedDirs = patterns.every(pattern => {
12241228
const resolvedPath = path.resolve(pattern)
12251229

12261230
// Check each allowed directory
1227-
for (const allowedDir of [
1228-
resolvedTmpDir,
1229-
resolvedCacacheDir,
1230-
resolvedSocketUserDir,
1231-
]) {
1231+
for (const allowedDir of allowedDirs) {
12321232
const isInAllowedDir =
12331233
resolvedPath.startsWith(allowedDir + path.sep) ||
12341234
resolvedPath === allowedDir

0 commit comments

Comments
 (0)