1111 *
1212 * Concurrency protection:
1313 * - Uses process-lock to prevent concurrent installation corruption
14- * - Lock file created at ~/.socket/_dlx/<hash>/.lock
15- * - Aligned with npm npx's concurrency.lock strategy (5s stale, 2s touching)
14+ * - Lock file created at ~/.socket/_dlx/<hash>/concurrency .lock
15+ * - Uses npm npx's concurrency.lock naming convention (5s stale, 2s touching)
1616 * - Prevents multiple processes from corrupting the same package installation
1717 *
1818 * Version range handling:
@@ -140,9 +140,34 @@ async function ensurePackageInstalled(
140140 path . join ( packageDir , 'node_modules' , packageName ) ,
141141 )
142142
143+ // Ensure package directory exists before creating lock.
144+ // The lock directory will be created inside this directory.
145+ try {
146+ await fs . mkdir ( packageDir , { recursive : true } )
147+ } catch ( e ) {
148+ const code = ( e as NodeJS . ErrnoException ) . code
149+ if ( code === 'EACCES' || code === 'EPERM' ) {
150+ throw new Error (
151+ `Permission denied creating package directory: ${ packageDir } \n` +
152+ 'Please check directory permissions or run with appropriate access.' ,
153+ { cause : e } ,
154+ )
155+ }
156+ if ( code === 'EROFS' ) {
157+ throw new Error (
158+ `Cannot create package directory on read-only filesystem: ${ packageDir } \n` +
159+ 'Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.' ,
160+ { cause : e } ,
161+ )
162+ }
163+ throw new Error ( `Failed to create package directory: ${ packageDir } ` , {
164+ cause : e ,
165+ } )
166+ }
167+
143168 // Use process lock to prevent concurrent installations.
144- // Similar to npm npx's concurrency.lock approach .
145- const lockPath = path . join ( packageDir , '.lock' )
169+ // Uses npm npx's concurrency.lock naming convention .
170+ const lockPath = path . join ( packageDir , 'concurrency .lock' )
146171
147172 return await processLock . withLock (
148173 lockPath ,
@@ -157,16 +182,38 @@ async function ensurePackageInstalled(
157182 }
158183 }
159184
160- // Ensure package directory exists.
161- await fs . mkdir ( packageDir , { recursive : true } )
162-
163185 // Use pacote to extract the package.
164186 // Pacote leverages npm cache when available but doesn't require npm CLI.
165187 const pacoteCachePath = getPacoteCachePath ( )
166- await pacote . extract ( packageSpec , installedDir , {
167- // Use consistent pacote cache path (respects npm cache locations when available).
168- cache : pacoteCachePath || path . join ( packageDir , '.cache' ) ,
169- } )
188+ try {
189+ await pacote . extract ( packageSpec , installedDir , {
190+ // Use consistent pacote cache path (respects npm cache locations when available).
191+ cache : pacoteCachePath || path . join ( packageDir , '.cache' ) ,
192+ } )
193+ } catch ( e ) {
194+ const code = ( e as any ) . code
195+ if ( code === 'E404' || code === 'ETARGET' ) {
196+ throw new Error (
197+ `Package not found: ${ packageSpec } \n` +
198+ 'Verify the package exists on npm registry and check the version.\n' +
199+ `Visit https://www.npmjs.com/package/${ packageName } to see available versions.` ,
200+ { cause : e } ,
201+ )
202+ }
203+ if ( code === 'ENOTFOUND' || code === 'ETIMEDOUT' || code === 'EAI_AGAIN' ) {
204+ throw new Error (
205+ `Network error installing ${ packageSpec } \n` +
206+ 'Check your internet connection and try again.' ,
207+ { cause : e } ,
208+ )
209+ }
210+ throw new Error (
211+ `Failed to install package: ${ packageSpec } \n` +
212+ `Destination: ${ installedDir } \n` +
213+ 'Check npm registry connectivity or package name.' ,
214+ { cause : e } ,
215+ )
216+ }
170217
171218 return { installed : true , packageDir }
172219 } ,
0 commit comments