@@ -213,7 +213,7 @@ export async function prepareBundleForDebugIdUpload(
213213 logger : Logger ,
214214 rewriteSourcesHook : RewriteSourcesHook
215215) {
216- let bundleContent ;
216+ let bundleContent : string ;
217217 try {
218218 bundleContent = await promisify ( fs . readFile ) ( bundleFilePath , "utf8" ) ;
219219 } catch ( e ) {
@@ -232,14 +232,11 @@ export async function prepareBundleForDebugIdUpload(
232232 return ;
233233 }
234234
235- const uniqueUploadName = `${ debugId } -${ chunkIndex } ` ;
236-
235+ const uniqueSourceFileUploadPath = getUniqueUploadPath ( uploadFolder , chunkIndex , bundleFilePath ) ;
237236 bundleContent += `\n//# debugId=${ debugId } ` ;
238- const writeSourceFilePromise = fs . promises . writeFile (
239- path . join ( uploadFolder , `${ uniqueUploadName } .js` ) ,
240- bundleContent ,
241- "utf-8"
242- ) ;
237+ const writeSourceFilePromise = fs . promises
238+ . mkdir ( path . dirname ( uniqueSourceFileUploadPath ) , { recursive : true } )
239+ . then ( ( ) => fs . promises . writeFile ( uniqueSourceFileUploadPath , bundleContent , "utf-8" ) ) ;
243240
244241 const writeSourceMapFilePromise = determineSourceMapPathFromBundle (
245242 bundleFilePath ,
@@ -249,7 +246,7 @@ export async function prepareBundleForDebugIdUpload(
249246 if ( sourceMapPath ) {
250247 await prepareSourceMapForDebugIdUpload (
251248 sourceMapPath ,
252- path . join ( uploadFolder , ` ${ uniqueUploadName } .js.map` ) ,
249+ getUniqueUploadPath ( uploadFolder , chunkIndex , sourceMapPath ) ,
253250 debugId ,
254251 rewriteSourcesHook ,
255252 logger
@@ -261,6 +258,27 @@ export async function prepareBundleForDebugIdUpload(
261258 await writeSourceMapFilePromise ;
262259}
263260
261+ function getUniqueUploadPath ( uploadFolder : string , chunkIndex : number , filePath : string ) {
262+ return path . join (
263+ uploadFolder ,
264+ // We add a "chunk index" segment to the path that is a simple incrementing number to avoid name collisions.
265+ // Name collisions can happen when files are located "outside" of the current working directory, at different levels but they share a subpath.
266+ // Example:
267+ // - CWD: /root/foo/cwd
268+ // - File 1: /root/foo/index.js -> ../foo/index.js -> foo/index.js
269+ // - File 2: /foo/index.js -> ../../foo/index.js -> foo/index.js
270+ `${ chunkIndex } ` ,
271+ path . normalize (
272+ path
273+ . relative ( process . cwd ( ) , filePath )
274+ . split ( path . sep )
275+ // We filter out these "navigation" segments because a) they look ugly b) they will cause us to break out of the upload folder.
276+ . filter ( ( segment ) => segment !== ".." && segment !== "." )
277+ . join ( path . sep )
278+ )
279+ ) ;
280+ }
281+
264282/**
265283 * Looks for a particular string pattern (`sdbid-[debug ID]`) in the bundle
266284 * source and extracts the bundle's debug ID from it.
@@ -379,7 +397,8 @@ async function prepareSourceMapForDebugIdUpload(
379397 }
380398
381399 try {
382- await util . promisify ( fs . writeFile ) ( targetPath , JSON . stringify ( map ) , {
400+ await fs . promises . mkdir ( path . dirname ( targetPath ) , { recursive : true } ) ;
401+ await fs . promises . writeFile ( targetPath , JSON . stringify ( map ) , {
383402 encoding : "utf8" ,
384403 } ) ;
385404 } catch ( e ) {
0 commit comments