@@ -213,7 +213,7 @@ export async function prepareBundleForDebugIdUpload(
213
213
logger : Logger ,
214
214
rewriteSourcesHook : RewriteSourcesHook
215
215
) {
216
- let bundleContent ;
216
+ let bundleContent : string ;
217
217
try {
218
218
bundleContent = await promisify ( fs . readFile ) ( bundleFilePath , "utf8" ) ;
219
219
} catch ( e ) {
@@ -232,14 +232,11 @@ export async function prepareBundleForDebugIdUpload(
232
232
return ;
233
233
}
234
234
235
- const uniqueUploadName = `${ debugId } -${ chunkIndex } ` ;
236
-
235
+ const uniqueSourceFileUploadPath = getUniqueUploadPath ( uploadFolder , chunkIndex , bundleFilePath ) ;
237
236
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" ) ) ;
243
240
244
241
const writeSourceMapFilePromise = determineSourceMapPathFromBundle (
245
242
bundleFilePath ,
@@ -249,7 +246,7 @@ export async function prepareBundleForDebugIdUpload(
249
246
if ( sourceMapPath ) {
250
247
await prepareSourceMapForDebugIdUpload (
251
248
sourceMapPath ,
252
- path . join ( uploadFolder , ` ${ uniqueUploadName } .js.map` ) ,
249
+ getUniqueUploadPath ( uploadFolder , chunkIndex , sourceMapPath ) ,
253
250
debugId ,
254
251
rewriteSourcesHook ,
255
252
logger
@@ -261,6 +258,27 @@ export async function prepareBundleForDebugIdUpload(
261
258
await writeSourceMapFilePromise ;
262
259
}
263
260
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
+
264
282
/**
265
283
* Looks for a particular string pattern (`sdbid-[debug ID]`) in the bundle
266
284
* source and extracts the bundle's debug ID from it.
@@ -379,7 +397,8 @@ async function prepareSourceMapForDebugIdUpload(
379
397
}
380
398
381
399
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 ) , {
383
402
encoding : "utf8" ,
384
403
} ) ;
385
404
} catch ( e ) {
0 commit comments