@@ -2,7 +2,7 @@ import crypto from 'node:crypto'
22import process from 'node:process'
33import { execFile } from 'node:child_process'
44import { promisify } from 'node:util'
5- import { mkdtemp , writeFile , rm } from 'node:fs/promises'
5+ import { mkdtempDisposable , writeFile } from 'node:fs/promises'
66import { tmpdir } from 'node:os'
77import { join } from 'node:path'
88import * as v from 'valibot'
@@ -569,91 +569,84 @@ export async function packageInit(
569569) : Promise < NpmExecResult > {
570570 validatePackageName ( name )
571571
572- // Create a temporary directory
573- const tempDir = await mkdtemp ( join ( tmpdir ( ) , 'npmx-init-' ) )
574-
575- try {
576- // Determine access type based on whether it's a scoped package
577- const isScoped = name . startsWith ( '@' )
578- const access = isScoped ? 'public' : undefined
579-
580- // Create minimal package.json
581- const packageJson = {
582- name,
583- version : '0.0.0' ,
584- description : `Placeholder for ${ name } ` ,
585- main : 'index.js' ,
586- scripts : { } ,
587- keywords : [ ] ,
588- author : author ? `${ author } (https://www.npmjs.com/~${ author } )` : '' ,
589- license : 'UNLICENSED' ,
590- private : false ,
591- ...( access && { publishConfig : { access } } ) ,
592- }
572+ // Let Node clean up the temp directory automatically when this scope exits.
573+ await using tempDir = await mkdtempDisposable ( join ( tmpdir ( ) , 'npmx-init-' ) )
574+
575+ // Determine access type based on whether it's a scoped package
576+ const isScoped = name . startsWith ( '@' )
577+ const access = isScoped ? 'public' : undefined
578+
579+ // Create minimal package.json
580+ const packageJson = {
581+ name,
582+ version : '0.0.0' ,
583+ description : `Placeholder for ${ name } ` ,
584+ main : 'index.js' ,
585+ scripts : { } ,
586+ keywords : [ ] ,
587+ author : author ? `${ author } (https://www.npmjs.com/~${ author } )` : '' ,
588+ license : 'UNLICENSED' ,
589+ private : false ,
590+ ...( access && { publishConfig : { access } } ) ,
591+ }
593592
594- await writeFile ( join ( tempDir , 'package.json' ) , JSON . stringify ( packageJson , null , 2 ) )
593+ await writeFile ( join ( tempDir . path , 'package.json' ) , JSON . stringify ( packageJson , null , 2 ) )
595594
596- // Create empty index.js
597- await writeFile ( join ( tempDir , 'index.js' ) , '// Placeholder\n' )
595+ // Create empty index.js
596+ await writeFile ( join ( tempDir . path , 'index.js' ) , '// Placeholder\n' )
598597
599- // Build npm publish args
600- const args = [ 'publish' ]
601- if ( access ) {
602- args . push ( '--access' , access )
603- }
598+ // Build npm publish args
599+ const args = [ 'publish' ]
600+ if ( access ) {
601+ args . push ( '--access' , access )
602+ }
604603
605- // Run npm publish from the temp directory
606- const npmArgs = otp ? [ ...args , '--otp' , otp ] : args
604+ // Run npm publish from the temp directory
605+ const npmArgs = otp ? [ ...args , '--otp' , otp ] : args
607606
608- // Log the command being run (hide OTP value for security)
609- const displayCmd = otp ? `npm ${ args . join ( ' ' ) } --otp ******` : `npm ${ args . join ( ' ' ) } `
610- logCommand ( `${ displayCmd } (in temp dir for ${ name } )` )
607+ // Log the command being run (hide OTP value for security)
608+ const displayCmd = otp ? `npm ${ args . join ( ' ' ) } --otp ******` : `npm ${ args . join ( ' ' ) } `
609+ logCommand ( `${ displayCmd } (in temp dir for ${ name } )` )
611610
612- try {
613- const { stdout, stderr } = await execFileAsync ( 'npm' , npmArgs , {
614- timeout : 60000 ,
615- cwd : tempDir ,
616- env : createNpmEnv ( ) ,
617- shell : process . platform === 'win32' ,
618- } )
611+ try {
612+ const { stdout, stderr } = await execFileAsync ( 'npm' , npmArgs , {
613+ timeout : 60000 ,
614+ cwd : tempDir . path ,
615+ env : createNpmEnv ( ) ,
616+ shell : process . platform === 'win32' ,
617+ } )
619618
620- logSuccess ( `Published ${ name } @0.0.0` )
619+ logSuccess ( `Published ${ name } @0.0.0` )
621620
622- return {
623- stdout : stdout . trim ( ) ,
624- stderr : filterNpmWarnings ( stderr ) ,
625- exitCode : 0 ,
626- }
627- } catch ( error ) {
628- const err = error as { stdout ?: string ; stderr ?: string ; code ?: number }
629- const stderr = err . stderr ?. trim ( ) ?? String ( error )
630- const requiresOtp = detectOtpRequired ( stderr )
631- const authFailure = detectAuthFailure ( stderr )
621+ return {
622+ stdout : stdout . trim ( ) ,
623+ stderr : filterNpmWarnings ( stderr ) ,
624+ exitCode : 0 ,
625+ }
626+ } catch ( error ) {
627+ const err = error as { stdout ?: string ; stderr ?: string ; code ?: number }
628+ const stderr = err . stderr ?. trim ( ) ?? String ( error )
629+ const requiresOtp = detectOtpRequired ( stderr )
630+ const authFailure = detectAuthFailure ( stderr )
632631
633- if ( requiresOtp ) {
634- logError ( 'OTP required' )
635- } else if ( authFailure ) {
636- logError ( 'Authentication required - please run "npm login" and restart the connector' )
637- } else {
638- logError ( filterNpmWarnings ( stderr ) . split ( '\n' ) [ 0 ] || 'Command failed' )
639- }
632+ if ( requiresOtp ) {
633+ logError ( 'OTP required' )
634+ } else if ( authFailure ) {
635+ logError ( 'Authentication required - please run "npm login" and restart the connector' )
636+ } else {
637+ logError ( filterNpmWarnings ( stderr ) . split ( '\n' ) [ 0 ] || 'Command failed' )
638+ }
640639
641- return {
642- stdout : err . stdout ?. trim ( ) ?? '' ,
643- stderr : requiresOtp
644- ? 'This operation requires a one-time password (OTP).'
645- : authFailure
646- ? 'Authentication failed. Please run "npm login" and restart the connector.'
647- : filterNpmWarnings ( stderr ) ,
648- exitCode : err . code ?? 1 ,
649- requiresOtp,
650- authFailure,
651- }
640+ return {
641+ stdout : err . stdout ?. trim ( ) ?? '' ,
642+ stderr : requiresOtp
643+ ? 'This operation requires a one-time password (OTP).'
644+ : authFailure
645+ ? 'Authentication failed. Please run "npm login" and restart the connector.'
646+ : filterNpmWarnings ( stderr ) ,
647+ exitCode : err . code ?? 1 ,
648+ requiresOtp,
649+ authFailure,
652650 }
653- } finally {
654- // Clean up temp directory
655- await rm ( tempDir , { recursive : true , force : true } ) . catch ( ( ) => {
656- // Ignore cleanup errors
657- } )
658651 }
659652}
0 commit comments