From be14a8d09b4e23474a7333b2cca732998d5d6ba2 Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Mon, 16 Feb 2026 15:30:29 +0000 Subject: [PATCH 1/4] fix: rename instead of copy temp files during import --- src/context.ts | 4 ++-- test/maps.test.ts | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/context.ts b/src/context.ts index 5df2103..7c68f57 100644 --- a/src/context.ts +++ b/src/context.ts @@ -155,11 +155,11 @@ export class Context { const existingReader = await existingReaderPromise await existingReader.close().catch(noop) } - 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', () => { From 5f59b3080003a15d1454dd4abe3bf59365889447 Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Mon, 16 Feb 2026 16:35:44 +0000 Subject: [PATCH 2/4] debug --- src/context.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/context.ts b/src/context.ts index 7c68f57..bdf10a6 100644 --- a/src/context.ts +++ b/src/context.ts @@ -145,15 +145,20 @@ 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.close().catch((e) => { + console.error('Error closing existing reader:', e) + }) } await fsPromises.rename(tempPath, mapFileUrl) return new Reader(fileURLToPath(mapFileUrl)) From 4c206383c1c9e94380709127bb2e9927bede3c3a Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Tue, 17 Feb 2026 10:38:58 +0000 Subject: [PATCH 3/4] add patches to close readers --- patches/styled-map-package+4.0.1.patch | 18 ++++++++++++++++++ patches/yauzl-promise+4.0.0.patch | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 patches/styled-map-package+4.0.1.patch create mode 100644 patches/yauzl-promise+4.0.0.patch 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; + } + From 27e2a3fe3a89265ab8a1e492d6ab650ad42a3cea Mon Sep 17 00:00:00 2001 From: Gregor MacLennan Date: Tue, 17 Feb 2026 10:55:21 +0000 Subject: [PATCH 4/4] attempt to fix close issue --- src/context.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/context.ts b/src/context.ts index bdf10a6..da36c6e 100644 --- a/src/context.ts +++ b/src/context.ts @@ -156,6 +156,7 @@ export class Context { if (existingReaderPromise) { console.log(`Closing existing reader for map ID "${mapId}"`) const existingReader = await existingReaderPromise + await existingReader.opened().catch(noop) // Ensure reader is fully opened before closing await existingReader.close().catch((e) => { console.error('Error closing existing reader:', e) })