11/** @fileoverview DLX binary execution utilities for Socket ecosystem. */
22
33import { createHash } from 'node:crypto'
4- import { existsSync , promises as fs } from 'node:fs'
54import os from 'node:os'
65import path from 'node:path'
76
87import { WIN32 } from '#constants/platform'
98
109import { generateCacheKey } from './dlx'
1110import { httpDownload } from './http-request'
12- import { isDir , readJson , safeDelete } from './fs'
11+ import { isDir , readJson , safeDelete , safeMkdir } from './fs'
1312import { isObjectObject } from './objects'
1413import { normalizePath } from './path'
1514import { getSocketDlxDir } from './paths'
1615import { processLock } from './process-lock'
1716import type { SpawnExtra , SpawnOptions } from './spawn'
1817import { spawn } from './spawn'
1918
19+ let _fs : typeof import ( 'fs' ) | undefined
20+ /**
21+ * Lazily load the fs module to avoid Webpack errors.
22+ * Uses non-'node:' prefixed require to prevent Webpack bundling issues.
23+ *
24+ * @returns The Node.js fs module
25+ * @private
26+ */
27+ /*@__NO_SIDE_EFFECTS__ */
28+ function getFs ( ) {
29+ if ( _fs === undefined ) {
30+ // Use non-'node:' prefixed require to avoid Webpack errors.
31+ _fs = /*@__PURE__ */ require ( 'fs' )
32+ }
33+ return _fs as typeof import ( 'fs' )
34+ }
35+
2036export interface DlxBinaryOptions {
2137 /** URL to download the binary from. */
2238 url : string
@@ -139,9 +155,10 @@ async function isCacheValid(
139155 cacheEntryPath : string ,
140156 cacheTtl : number ,
141157) : Promise < boolean > {
158+ const fs = getFs ( )
142159 try {
143160 const metaPath = getMetadataPath ( cacheEntryPath )
144- if ( ! existsSync ( metaPath ) ) {
161+ if ( ! fs . existsSync ( metaPath ) ) {
145162 return false
146163 }
147164
@@ -181,12 +198,13 @@ async function downloadBinaryFile(
181198 return await processLock . withLock (
182199 lockPath ,
183200 async ( ) => {
201+ const fs = getFs ( )
184202 // Check if file was downloaded while waiting for lock.
185- if ( existsSync ( destPath ) ) {
186- const stats = await fs . stat ( destPath )
203+ if ( fs . existsSync ( destPath ) ) {
204+ const stats = await fs . promises . stat ( destPath )
187205 if ( stats . size > 0 ) {
188206 // File exists, compute and return checksum.
189- const fileBuffer = await fs . readFile ( destPath )
207+ const fileBuffer = await fs . promises . readFile ( destPath )
190208 const hasher = createHash ( 'sha256' )
191209 hasher . update ( fileBuffer )
192210 return hasher . digest ( 'hex' )
@@ -206,7 +224,7 @@ async function downloadBinaryFile(
206224 }
207225
208226 // Compute checksum of downloaded file.
209- const fileBuffer = await fs . readFile ( destPath )
227+ const fileBuffer = await fs . promises . readFile ( destPath )
210228 const hasher = createHash ( 'sha256' )
211229 hasher . update ( fileBuffer )
212230 const actualChecksum = hasher . digest ( 'hex' )
@@ -222,7 +240,7 @@ async function downloadBinaryFile(
222240
223241 // Make executable on POSIX systems.
224242 if ( ! WIN32 ) {
225- await fs . chmod ( destPath , 0o755 )
243+ await fs . promises . chmod ( destPath , 0o755 )
226244 }
227245
228246 return actualChecksum
@@ -264,7 +282,8 @@ async function writeMetadata(
264282 url,
265283 } ,
266284 }
267- await fs . writeFile ( metaPath , JSON . stringify ( metadata , null , 2 ) )
285+ const fs = getFs ( )
286+ await fs . promises . writeFile ( metaPath , JSON . stringify ( metadata , null , 2 ) )
268287}
269288
270289/**
@@ -274,14 +293,15 @@ export async function cleanDlxCache(
274293 maxAge : number = /*@__INLINE__ */ require ( '#constants/time' ) . DLX_BINARY_CACHE_TTL ,
275294) : Promise < number > {
276295 const cacheDir = getDlxCachePath ( )
296+ const fs = getFs ( )
277297
278- if ( ! existsSync ( cacheDir ) ) {
298+ if ( ! fs . existsSync ( cacheDir ) ) {
279299 return 0
280300 }
281301
282302 let cleaned = 0
283303 const now = Date . now ( )
284- const entries = await fs . readdir ( cacheDir )
304+ const entries = await fs . promises . readdir ( cacheDir )
285305
286306 for ( const entry of entries ) {
287307 const entryPath = path . join ( cacheDir , entry )
@@ -319,7 +339,7 @@ export async function cleanDlxCache(
319339 // If we can't read metadata, check if directory is empty or corrupted.
320340 try {
321341 // eslint-disable-next-line no-await-in-loop
322- const contents = await fs . readdir ( entryPath )
342+ const contents = await fs . promises . readdir ( entryPath )
323343 if ( ! contents . length ) {
324344 // Remove empty directory.
325345 // eslint-disable-next-line no-await-in-loop
@@ -358,14 +378,15 @@ export async function dlxBinary(
358378 const cacheKey = generateCacheKey ( spec )
359379 const cacheEntryDir = path . join ( cacheDir , cacheKey )
360380 const binaryPath = normalizePath ( path . join ( cacheEntryDir , binaryName ) )
381+ const fs = getFs ( )
361382
362383 let downloaded = false
363384 let computedChecksum = checksum
364385
365386 // Check if we need to download.
366387 if (
367388 ! force &&
368- existsSync ( cacheEntryDir ) &&
389+ fs . existsSync ( cacheEntryDir ) &&
369390 ( await isCacheValid ( cacheEntryDir , cacheTtl ) )
370391 ) {
371392 // Binary is cached and valid, read the checksum from metadata.
@@ -396,7 +417,7 @@ export async function dlxBinary(
396417 if ( downloaded ) {
397418 // Ensure cache directory exists before downloading.
398419 try {
399- await fs . mkdir ( cacheEntryDir , { recursive : true } )
420+ await safeMkdir ( cacheEntryDir , { recursive : true } )
400421 } catch ( e ) {
401422 const code = ( e as NodeJS . ErrnoException ) . code
402423 if ( code === 'EACCES' || code === 'EPERM' ) {
@@ -423,7 +444,7 @@ export async function dlxBinary(
423444 computedChecksum = await downloadBinaryFile ( url , binaryPath , checksum )
424445
425446 // Get file size for metadata.
426- const stats = await fs . stat ( binaryPath )
447+ const stats = await fs . promises . stat ( binaryPath )
427448 await writeMetadata (
428449 cacheEntryDir ,
429450 cacheKey ,
@@ -497,21 +518,22 @@ export async function downloadBinary(
497518 const cacheKey = generateCacheKey ( spec )
498519 const cacheEntryDir = path . join ( cacheDir , cacheKey )
499520 const binaryPath = normalizePath ( path . join ( cacheEntryDir , binaryName ) )
521+ const fs = getFs ( )
500522
501523 let downloaded = false
502524
503525 // Check if we need to download.
504526 if (
505527 ! force &&
506- existsSync ( cacheEntryDir ) &&
528+ fs . existsSync ( cacheEntryDir ) &&
507529 ( await isCacheValid ( cacheEntryDir , cacheTtl ) )
508530 ) {
509531 // Binary is cached and valid.
510532 downloaded = false
511533 } else {
512534 // Ensure cache directory exists before downloading.
513535 try {
514- await fs . mkdir ( cacheEntryDir , { recursive : true } )
536+ await safeMkdir ( cacheEntryDir , { recursive : true } )
515537 } catch ( e ) {
516538 const code = ( e as NodeJS . ErrnoException ) . code
517539 if ( code === 'EACCES' || code === 'EPERM' ) {
@@ -538,7 +560,7 @@ export async function downloadBinary(
538560 const computedChecksum = await downloadBinaryFile ( url , binaryPath , checksum )
539561
540562 // Get file size for metadata.
541- const stats = await fs . stat ( binaryPath )
563+ const stats = await fs . promises . stat ( binaryPath )
542564 await writeMetadata (
543565 cacheEntryDir ,
544566 cacheKey ,
@@ -623,14 +645,15 @@ export async function listDlxCache(): Promise<
623645 } >
624646> {
625647 const cacheDir = getDlxCachePath ( )
648+ const fs = getFs ( )
626649
627- if ( ! existsSync ( cacheDir ) ) {
650+ if ( ! fs . existsSync ( cacheDir ) ) {
628651 return [ ]
629652 }
630653
631654 const results = [ ]
632655 const now = Date . now ( )
633- const entries = await fs . readdir ( cacheDir )
656+ const entries = await fs . promises . readdir ( cacheDir )
634657
635658 for ( const entry of entries ) {
636659 const entryPath = path . join ( cacheDir , entry )
@@ -661,13 +684,13 @@ export async function listDlxCache(): Promise<
661684
662685 // Find the binary file in the directory.
663686 // eslint-disable-next-line no-await-in-loop
664- const files = await fs . readdir ( entryPath )
687+ const files = await fs . promises . readdir ( entryPath )
665688 const binaryFile = files . find ( f => ! f . startsWith ( '.' ) )
666689
667690 if ( binaryFile ) {
668691 const binaryPath = path . join ( entryPath , binaryFile )
669692 // eslint-disable-next-line no-await-in-loop
670- const binaryStats = await fs . stat ( binaryPath )
693+ const binaryStats = await fs . promises . stat ( binaryPath )
671694
672695 results . push ( {
673696 age : now - ( ( metaObj [ 'timestamp' ] as number ) || 0 ) ,
0 commit comments