From 38b542def44d11dcdd27ccfc422aa857c8841d77 Mon Sep 17 00:00:00 2001 From: devlikepro Date: Wed, 2 Jul 2025 13:01:00 +0700 Subject: [PATCH] [core] Add TmpDir (from PLUS) --- src/utils/tmpdir.ts | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/utils/tmpdir.ts diff --git a/src/utils/tmpdir.ts b/src/utils/tmpdir.ts new file mode 100644 index 00000000..4670ed52 --- /dev/null +++ b/src/utils/tmpdir.ts @@ -0,0 +1,47 @@ +import * as fs from 'fs/promises'; +import * as os from 'os'; +import * as path from 'path'; +import { Logger } from 'pino'; + +function sanitize(input: string) { + return input.replace(/[^a-zA-Z0-9-_]/g, '_'); +} + +export class TmpDir { + private readonly prefix: string; + constructor( + private logger: Logger, + prefix: string, + private cleanupTimeout = 10_000, + ) { + this.prefix = sanitize(prefix); + if (this.prefix.length > 249) { + this.prefix = this.prefix.slice(0, 249); + } + } + + /** + * Creates a temporary directory and passes it to the callback. + * The directory is automatically cleaned up after the callback returns. + * @param callback Function that receives the temporary directory path + * @returns The result of the callback + */ + public async use(callback: (dir: string) => Promise): Promise { + const dir = await fs.mkdtemp(path.join(os.tmpdir(), this.prefix)); + try { + return await callback(dir); + } finally { + setTimeout(async () => { + fs.rm(dir, { recursive: true, force: true }) + .then(() => { + this.logger.trace(`Cleaned up temporary directory '${dir}'`); + }) + .catch((err) => { + this.logger.warn( + `Failed to clean up temporary directory '${dir}': ${err.message}`, + ); + }); + }, this.cleanupTimeout); + } + } +}