A comprehensive Node.js-specific utility library extending@dooboostore/corewith file system operations, process management, memory profiling, and batch HTTP downloading capabilities. Perfect for backend services, CLI tools, SSR applications, and DevOps workflows.
FileUtils.File<E>class with copy/move/delete/rename operations plus promise/sync read/write helpers—no raw fs callbacksHttpPageDownloaderfor SSR to static HTML generation (pre-rendering workflows)pathmodulefs/path/process/v8/os— no third-party runtime depsexportsentry is./bundle-entry@dooboostore/core-nodedepends on@dooboostore/core(installed automatically) and peer-depends onreflect-metadata:
# pnpm (recommended)pnpm add @dooboostore/core-node reflect-metadata# npmnpm install @dooboostore/core-node reflect-metadata# yarnyarn add @dooboostore/core-node reflect-metadata@dooboostore/core-nodeincludes6 focused modules:
| Module | Purpose | Key Exports |
|---|---|---|
| file | File system operations | FileUtils,FileUtils.File<E>class |
| fetch | HTTP page downloading | HttpPageDownloader |
| process | Process information | ProcessUtils(PID, platform, env) |
| memory | Memory profiling | MemoryUtils(heap snapshots, monitoring) |
| path | Path operations | PathUtils(join, resolve, normalize) |
| convert | Data conversion | ConvertUtils(Buffer ↔ String, Base64) |
File system helpers plus an object-orientedFileUtils.File<E>class (a namespace member, not a top-level export).
// FileUtils.FileclassFile<E =any> {constructor(data: { path:string; originalName?:string; etcData?: E })// Note: the constructor calls updateStats() without awaiting it, so `size` is filled asynchronously.// Call `await file.updateStats()` before reading `size` on a freshly constructed File.// Propertiesgetpath():string// Full file pathgetfileName():string// Just the filename (substring after the last '/')getdirectory():string// Directory path (substring before the last '/')getextension():string|undefined// Text after the last '.' (undefined only if the path ends in '.')getoriginalName():string|undefined// Original filename passed in when constructedsize:number|undefined// File size in bytes (populated by updateStats())etcData: E// Generic metadata// MethodsasyncupdateStats():Promise<void>// Refresh file statsasyncdelete():Promise<void>// Delete the fileasynccopy(newPath:string):Promise<void>// Copy to newPath; this File then points at the copyasyncmove(newPath:string):Promise<void>// Move to newPath (a full path incl. file name; creates dirs if needed)asyncrename(newName:string):Promise<void>// Rename within the same directory}PathParamTypeaccepted throughout isstring | string[]— an array is joined viapath.join(...).
// Write a Buffer to a file (auto-generates an OS temp path if config.path is omitted)writeFile<E =any>(buffer:Buffer,config?: {path?:string// defaults to `${os.tmpdir()}/${uuid4()}_${Date.now()}`originalName?:string// original filename, stored as File.originalNameetcData?: E// generic metadata, stored as File.etcData}):Promise<File<E>>// ReadreadSync(path:PathParamType,config?: {option?: fs.readFileSync2nd arg }):BufferreadAsync(path:PathParamType,config?: {option?: fs.promises.readFile2nd arg }):Promise<Buffer>read(path:PathParamType,config: {option: fs.readFile2nd arg }):Promise<Buffer>// callback-style fs.readFile, promisified by returnreadJsonSync<T =any>(path:PathParamType): T
readJsonAsync<T =any>(path:PathParamType):Promise<T>readStringSync(path:PathParamType):string// reads as 'utf-8'readStringAsync(path:PathParamType):Promise<string>// reads as 'utf-8'// Writewrite(data:string|Buffer,config: {path:PathParamType,options?: fs.WriteFileOptions}):string// returns the resolved pathwriteAppend(data:string|Buffer,config: {path:PathParamType,options?: fs.WriteFileOptions}):string// DeletedeleteSync(path:PathParamType,config?: {options?: fs.RmOptions}):void// fs.rmSync, only if it existsdeleteDirSync(path:PathParamType,config?: {options?: fs.RmDirOptions}):void// fs.rmdirSync, only if it existsdeleteFileSync(path:PathParamType):void// fs.unlinkSync, only if it exists// CopycopySync(source:PathParamType,destination:PathParamType,options?: fs.cpSync3rd arg):void// Directory operationsmkdirSync(path:PathParamType,config?:MakeDirectoryOptions):voidmkdir(path:PathParamType,config?:MakeDirectoryOptions):Promise<string>// Note: the callback keys are spelled `existes`/`noExistes` (typo preserved from the source), not `exists`/`noExists`existsSync(path:PathParamType,config?: {existes?:(path:string) =>void,noExistes?:(path:string) =>void}):boolean// Path handlingpath(pathParam:PathParamType):string// joins an array with path.join(...), or returns the string as-isimport{FileUtils}from'@dooboostore/core-node';interfaceUploadMetadata{userId:string;uploadedAt:Date;mimeType?:string;
}asyncfunctionhandleFileUpload(buffer:Buffer,metadata:UploadMetadata) {// Save file with metadataconstfile =awaitFileUtils.writeFile<UploadMetadata>(buffer, {path:'./uploads/user-files/document.pdf',originalName:'my-document.pdf',etcData: metadata
});awaitfile.updateStats();// size is filled asynchronously by the constructorconsole.log(`File saved:${file.path}`);console.log(`Size:${file.size}bytes`);console.log(`User ID:${file.etcData?.userId}`);// Rename after processing (in ./uploads/user-files)awaitfile.rename('document-processed.pdf');// Copy to backup — note: `file` now points at the backup copyawaitfile.copy('./backups/document-processed.pdf');returnfile;
}Batch download HTML pages from a running server for SSR pre-rendering workflows.
classHttpPageDownloader{constructor(baseUrl:string,// e.g., 'http://localhost:3000'httpFetcher:HttpFetcher=newHttpFetcher()// Optional custom fetcher)// Methodsasyncdownload(route:string):Promise<string>// GET `${baseUrl}${route}` and return the body textasyncdownloadAndSave(outputDir:string,route:string):Promise<void>// writes <outputDir>/<route>/index.html ('/' -> <outputDir>/index.html); logs and swallows errorsasyncdownloadAndSaveAll(outputDir:string,routes:string[]):Promise<void>// calls downloadAndSave for each route sequentially}BecausedownloadAndSavecatches and logs errors instead of throwing,downloadAndSaveAllnever rejects on a failed route — check the console output.
import{HttpPageDownloader}from'@dooboostore/core-node';asyncfunctiongenerateStaticSite() {constdownloader =newHttpPageDownloader('http://localhost:3000');constroutes = ['/','/about','/products','/products/1','/contact'];// Generate all static HTML filesawaitdownloader.downloadAndSaveAll('./dist', routes);console.log('✅ Static site generated in ./dist');
}generateStaticSite();Access to Node.js process information and environment variables.
A thin, directly-named wrapper around Node's globalprocessobject.
// Runtime identityProcessUtils.getPid():number// process.pidProcessUtils.getPlatform():NodeJS.Platform// process.platform ('darwin' | 'linux' | 'win32' | ...)ProcessUtils.getArch():string// process.archProcessUtils.getNodeVersion():string// process.versionProcessUtils.getVersions():NodeJS.ProcessVersions// process.versions (node, v8, openssl, ...)ProcessUtils.getTitle():string// process.titleProcessUtils.getCwd():string// process.cwd()ProcessUtils.getUptime():number// process.uptime()ProcessUtils.getCpuUsage():NodeJS.CpuUsage// process.cpuUsage()ProcessUtils.getArgv():string[]// process.argv (NOT sliced — includes the node binary and script path)// EnvironmentProcessUtils.getEnv(key:string):string|undefined// process.env[key]ProcessUtils.setEnv(key:string,value:string):void// process.env[key] = valueProcessUtils.isProduction():boolean// process.env.NODE_ENV === 'production'ProcessUtils.isDevelopment():boolean// process.env.NODE_ENV === 'development' || NODE_ENV is unsetProcessUtils.isTest():boolean// process.env.NODE_ENV === 'test'// Process controlProcessUtils.exit(code:number=0):void// process.exit(code)import{ProcessUtils}from'@dooboostore/core-node';constconfig = {isDev:ProcessUtils.isDevelopment(),port:Number(ProcessUtils.getEnv('PORT')) ||3000,database:ProcessUtils.getEnv('DATABASE_URL') ||'localhost:5432'};console.log('🚀 Starting server...');console.log(` PID:${ProcessUtils.getPid()}`);console.log(` Platform:${ProcessUtils.getPlatform()}(${ProcessUtils.getArch()})`);console.log(` Environment:${ProcessUtils.isProduction() ?'Production':'Development'}`);Monitor heap usage and generate memory snapshots for debugging.
// Raw memory usage (bytes — same shape as process.memoryUsage())MemoryUtils.memoryUsage():NodeJS.MemoryUsage// { rss, heapTotal, heapUsed, external, arrayBuffers }// Logs memory usage to the console, converted to MBMemoryUtils.logMemoryUsage():void// Writes a V8 heap snapshot into `logPath` (a directory), filename is heap-<ISO timestamp>.heapsnapshot// Returns the written file path, or null if v8.writeHeapSnapshot threwMemoryUtils.writeHeapSnapshot(logPath:string):string|null// Registers a SIGUSR2 handler that calls writeHeapSnapshot(logPath) when the process receives SIGUSR2// (e.g. `kill -SIGUSR2 <pid>`, or `pm2 sendSignal SIGUSR2 <app-name>`)MemoryUtils.registerHeapDumpSignal(logPath:string):void// Starts a setInterval that calls logMemoryUsage() every `intervalMs`, and if `thresholdMB`// is exceeded, warns and (if `logPath` is given) writes an automatic heap snapshot.// Returns the interval handle so you can clearInterval() it later.MemoryUtils.startMemoryMonitoring(intervalMs?:number/* default 5 min */,thresholdMB?:number,logPath?:string):NodeJS.Timeoutimport{MemoryUtils}from'@dooboostore/core-node';// Log memory every 30s, and auto-dump a heap snapshot into ./heaps if usage exceeds 500MBMemoryUtils.startMemoryMonitoring(30_000,500,'./heaps');// Also dump on demand via `kill -SIGUSR2 <pid>`MemoryUtils.registerHeapDumpSignal('./heaps');Wrapper around Node.jspathmodule with type-safe handling.
A direct, one-to-one wrapper around Node'spathmodule (plusprocessCwd()forprocess.cwd()). Every function takes plain string arguments — unlikeFileUtils'sPathParamType, it doesnotaccept an array in place of the rest-args.
PathUtils.processCwd():string// process.cwd()PathUtils.join(...paths:string[]):string// path.join(...)PathUtils.resolve(...paths:string[]):string// path.resolve(...)PathUtils.normalize(path:string):string// path.normalize(path)PathUtils.dirname(path:string):string// path.dirname(path)PathUtils.basename(path:string,suffix?:string):string// path.basename(path, suffix)PathUtils.extname(path:string):string// path.extname(path)PathUtils.isAbsolute(path:string):boolean// path.isAbsolute(path)PathUtils.relative(from:string,to:string):string// path.relative(from, to)PathUtils.parse(path:string): path.ParsedPath// path.parse(path)PathUtils.format(pathObject: path.FormatInputPathObject):string// path.format(pathObject)import{PathUtils}from'@dooboostore/core-node';constconfigPath =PathUtils.join('./config','env','production.json');// Parse file partsconstparsed =PathUtils.parse('/app/src/index.ts');// { root: '/', dir: '/app/src', base: 'index.ts', ext: '.ts', name: 'index' }Convert between Buffers, strings, and handle Base64 encoding/decoding.
// Buffer (or string, passed through unchanged) to StringConvertUtils.toString(data:string|Buffer,config?: {encoding?:BufferEncoding// default: 'utf-8'; forwarded to Buffer#toString(encoding, start, end)start?:numberend?:number}):string// String to BufferConvertUtils.toBuffer(data:string,config?: {encoding:BufferEncoding}):BuffertoBufferonly special-casesconfig.encoding === 'base64': it strips an optional Data URL prefix
(everything up to and including;base64,, e.g."data:image/png;base64,iVBORw0KGgo...") and decodes
the rest as base64. For any other (or missing)encoding, it returnsBuffer.from(data)(UTF-8) —
other encoding values are not applied.
import{ConvertUtils,FileUtils}from'@dooboostore/core-node';asyncfunctionsaveBase64Image(dataUrl:string) {// Handle data URLs: "data:image/png;base64,iVBORw0KGgo..."constbuffer =ConvertUtils.toBuffer(dataUrl, {encoding:'base64'});constfile =awaitFileUtils.writeFile(buffer, {path:'./uploads/image.png',originalName:'avatar.png'});returnfile.path;
}import{FileUtils}from'@dooboostore/core-node';interfaceUploadMetadata{userId:string;uploadedAt:Date;fileSize:number;
}asyncfunctionhandleUpload(buffer:Buffer,userId:string) {constfile =awaitFileUtils.writeFile<UploadMetadata>(buffer, {path:`./uploads/${userId}/document.pdf`,originalName:'resume.pdf',etcData: {
userId,uploadedAt:newDate(),fileSize: buffer.length}
});awaitfile.updateStats();console.log(`✅ Saved:${file.fileName}(${file.size}bytes)`);awaitfile.copy(`./backups/${userId}-${Date.now()}.pdf`);// `file` now points at the backupreturnfile;
}import{HttpPageDownloader}from'@dooboostore/core-node';import{ProcessUtils}from'@dooboostore/core-node';asyncfunctionbuildStaticSite() {constbaseUrl =ProcessUtils.getEnv('BUILD_URL') ||'http://localhost:3000';constdownloader =newHttpPageDownloader(baseUrl);constroutes = ['/','/about','/products','/contact'];awaitdownloader.downloadAndSaveAll('./dist', routes);console.log(`✨ Generated${routes.length}static pages`);
}import{ProcessUtils}from'@dooboostore/core-node';constconfig = {environment:ProcessUtils.isProduction() ?'production':'development',port:Number(ProcessUtils.getEnv('PORT')) ||3000,debug:ProcessUtils.getEnv('DEBUG') ==='true'};import{MemoryUtils}from'@dooboostore/core-node';// Enable SIGUSR2 heap profiling — `kill -SIGUSR2 <pid>` dumps a snapshot into ./heap-dumpsMemoryUtils.registerHeapDumpSignal('./heap-dumps');// Also log + auto-dump every 30s if heap usage exceeds 500MBMemoryUtils.startMemoryMonitoring(30_000,500,'./heap-dumps');core-nodedepends on@dooboostore/corefor two things specifically:HttpPageDownloaderusescore'sHttpFetcher/HttpFetcherRequestto perform the actual HTTP GET, andFileUtils.writeFileusescore'sRandomUtils.uuid4()to generate a temp file name when nopathis given. Everything else in this package (file, process, memory, path, convert) is implemented directly on Node.js built-ins and has no further dependency oncore.
| Feature | @dooboostore/core-node |
|---|---|
| File I/O | ✅ |
| Process/Env | ✅ |
| Memory Profiling | ✅ |
| Buffer/Base64 Conversion | ✅ |
| Path Operations | ✅ |
| HTTP page fetching | ✅ (viacore'sHttpFetcher) |
FileUtils.File<E>for type-safe metadata—etcDatacarries whatever metadata you need alongside the file.MemoryUtils.registerHeapDumpSignal(dir)lets you trigger a heap snapshot on demand viakill -SIGUSR2 <pid>, without restarting the process.ProcessUtilsfor environment checks—isProduction()/isDevelopment()/isTest()readNODE_ENVconsistently.PathUtilsfor cross-platform path handlinginstead of string concatenation.This package is licensed under theMIT License.