diff --git a/patches/styled-map-package+4.0.1.patch b/patches/styled-map-package+4.0.1.patch new file mode 100644 index 0000000..daf35d0 --- /dev/null +++ b/patches/styled-map-package+4.0.1.patch @@ -0,0 +1,18 @@ +diff --git a/node_modules/styled-map-package/.DS_Store b/node_modules/styled-map-package/.DS_Store +new file mode 100644 +index 0000000..4b95902 +Binary files /dev/null and b/node_modules/styled-map-package/.DS_Store differ +diff --git a/node_modules/styled-map-package/dist/reader.js b/node_modules/styled-map-package/dist/reader.js +index 75482d9..430c90d 100644 +--- a/node_modules/styled-map-package/dist/reader.js ++++ b/node_modules/styled-map-package/dist/reader.js +@@ -117,7 +117,8 @@ class Reader { + async close() { + if (this.#closePromise) return this.#closePromise; + this.#closePromise = (async () => { +- const zip = await this.#zipPromise; ++ const zip = await this.#zipPromise.catch(noop); ++ if (!zip) return; + await zip.close(); + })(); + return this.#closePromise; diff --git a/patches/yauzl-promise+4.0.0.patch b/patches/yauzl-promise+4.0.0.patch new file mode 100644 index 0000000..0a2b64f --- /dev/null +++ b/patches/yauzl-promise+4.0.0.patch @@ -0,0 +1,18 @@ +diff --git a/node_modules/yauzl-promise/lib/index.js b/node_modules/yauzl-promise/lib/index.js +index 8cb0e6c..a1aa47b 100644 +--- a/node_modules/yauzl-promise/lib/index.js ++++ b/node_modules/yauzl-promise/lib/index.js +@@ -54,7 +54,12 @@ async function open(path, options) { + const {size} = await fstatAsync(reader.fd); + + const zip = new Zip(INTERNAL_SYMBOL, reader, size, options); +- await zip._init(); ++ try { ++ await zip._init(); ++ } catch (err) { ++ await reader.close(); ++ throw err; ++ } + return zip; + } + diff --git a/src/context.ts b/src/context.ts index 5df2103..da36c6e 100644 --- a/src/context.ts +++ b/src/context.ts @@ -145,21 +145,27 @@ export class Context { await fsPromises.unlink(tempPath).catch(noop) throw new errors.INVALID_MAP_FILE() } finally { - await tempReader.close().catch(noop) + await tempReader.close().catch((e) => { + console.error('Error closing temp reader:', e) + }) } // Graceful replacement of SMP Reader when map file is updated const readerPromise = (async () => { const existingReaderPromise = this.#mapReaders.get(mapId) if (existingReaderPromise) { + console.log(`Closing existing reader for map ID "${mapId}"`) const existingReader = await existingReaderPromise - await existingReader.close().catch(noop) + await existingReader.opened().catch(noop) // Ensure reader is fully opened before closing + await existingReader.close().catch((e) => { + console.error('Error closing existing reader:', e) + }) } - await fsPromises.cp(tempPath, mapFileUrl, { force: true }) + await fsPromises.rename(tempPath, mapFileUrl) return new Reader(fileURLToPath(mapFileUrl)) })() this.#mapReaders.set(mapId, readerPromise) - // Wait for the file copy to complete before closing the stream + // Wait for the file rename to complete before closing the stream await readerPromise }, async abort(err) { diff --git a/test/maps.test.ts b/test/maps.test.ts index 9b0799b..3319341 100644 --- a/test/maps.test.ts +++ b/test/maps.test.ts @@ -569,6 +569,28 @@ describe('Map Upload', () => { const style = await styleResponse.json() expect(style).toEqual(expectedStyle) }) + + it('should not leave temp files after successful upload', async (t) => { + const { localBaseUrl, customMapPath } = await startServer(t, { + customMapPath: nonExistentPath, + }) + const tmpDir = path.dirname(customMapPath) + const customMapBasename = path.basename(customMapPath) + + const fileBuffer = fs.readFileSync(OSM_BRIGHT_Z6) + const response = await fetch(`${localBaseUrl}/maps/custom`, { + method: 'PUT', + body: fileBuffer, + headers: { 'Content-Type': 'application/octet-stream' }, + }) + expect(response.status).toBe(200) + + const filesInDir = fs.readdirSync(tmpDir) + const tempFiles = filesInDir.filter( + (f) => f.startsWith(customMapBasename) && f.includes('.download-'), + ) + expect(tempFiles).toHaveLength(0) + }) }) describe('Invalid Map Uploads', () => {