npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yamf/services-file-upload

v0.1.5

Published

File upload service for YAMF microservices with multipart/form-data support

Readme

@yamf/services-file-upload

Multipart file upload service for YAMF microservices with validation and metadata extraction.

Version License

Installation

npm install @yamf/services-file-upload

Note: This service requires the busboy package as a runtime dependency (the only YAMF service with external dependencies).

Quick Start

import { createFileUploadService } from '@yamf/services-file-upload'

const uploadService = await createFileUploadService({
  uploadDir: './uploads',
  fileFieldName: 'file',
  textFields: ['title', 'description'],
  validateFile: (filename, mimetype) => {
    return mimetype.startsWith('image/')
  }
})

// Upload via HTTP POST with multipart/form-data
// POST /upload
// Content-Type: multipart/form-data; boundary=----...
// 
// File will be saved to ./uploads/filename-timestamp.ext

Features

  • Multipart Form Data - Standard HTML form uploads
  • File Validation - Custom validation callbacks
  • Metadata Extraction - Capture additional form fields
  • Unique Filenames - Automatic timestamp-based naming
  • Error Handling - Comprehensive error messages
  • Stream Processing - Memory-efficient file handling

Configuration

await createFileUploadService({
  uploadDir: './uploads',           // Directory for uploaded files
  fileFieldName: 'file',            // Form field name for file
  textFields: ['title', 'author'],  // Additional fields to capture
  maxFileSize: 10485760,            // 10MB limit (optional)
  validateFile: (filename, mimetype) => {
    // Return true to allow, false to reject
    const allowed = ['image/jpeg', 'image/png', 'application/pdf']
    return allowed.includes(mimetype)
  }
})

Usage

HTML Form

<form action="/upload" method="POST" enctype="multipart/form-data">
  <input type="text" name="title" placeholder="Title">
  <input type="text" name="description" placeholder="Description">
  <input type="file" name="file">
  <button type="submit">Upload</button>
</form>

JavaScript Fetch

const formData = new FormData()
formData.append('title', 'My Document')
formData.append('description', 'Important file')
formData.append('file', fileInput.files[0])

const response = await fetch('/upload', {
  method: 'POST',
  body: formData
})

const result = await response.json()
console.log(result)
// {
//   success: true,
//   filename: 'document-1234567890.pdf',
//   metadata: {
//     title: 'My Document',
//     description: 'Important file'
//   }
// }

With YAMF Routes

import { createRoute } from '@yamf/core'
import { createFileUploadService } from '@yamf/services-file-upload'

// Create upload service
await createFileUploadService({
  uploadDir: './uploads',
  fileFieldName: 'audio',
  textFields: ['title', 'artist', 'album']
})

// Create route for uploads
await createRoute('/api/upload', 'fileUploadService')

File Validation

Validate by MIME Type

validateFile: (filename, mimetype) => {
  return mimetype.startsWith('image/')
}

Validate by Extension

validateFile: (filename, mimetype) => {
  const ext = filename.split('.').pop().toLowerCase()
  return ['jpg', 'jpeg', 'png', 'gif'].includes(ext)
}

Validate by Size and Type

validateFile: (filename, mimetype, size) => {
  const maxSize = 5 * 1024 * 1024 // 5MB
  const allowedTypes = ['image/jpeg', 'image/png']
  
  return size <= maxSize && allowedTypes.includes(mimetype)
}

Response Format

Success

{
  "success": true,
  "filename": "myfile-1701234567890.jpg",
  "path": "/uploads/myfile-1701234567890.jpg",
  "metadata": {
    "title": "Sunset Photo",
    "description": "Beautiful sunset"
  }
}

Validation Error

{
  "error": "File validation failed",
  "filename": "document.exe",
  "mimetype": "application/x-msdownload"
}

Upload Error

{
  "error": "File upload failed",
  "message": "Disk quota exceeded"
}

Security Considerations

  • Validate File Types - Always validate MIME types and extensions
  • Limit File Sizes - Set reasonable file size limits
  • Sanitize Filenames - Service automatically generates safe filenames
  • Directory Permissions - Ensure upload directory has correct permissions
  • Virus Scanning - Consider integrating virus scanning for production use

Common Patterns

Image Upload with Processing

await createFileUploadService({
  uploadDir: './temp',
  validateFile: (filename, mimetype) => mimetype.startsWith('image/'),
  onFileUploaded: async (filepath, metadata) => {
    // Process image (resize, convert, etc.)
    const processed = await processImage(filepath)
    
    // Move to final location
    await moveFile(processed, './images/')
    
    // Clean up temp file
    await unlink(filepath)
  }
})

Audio File Uploads

await createFileUploadService({
  uploadDir: './audio',
  fileFieldName: 'track',
  textFields: ['title', 'artist', 'album', 'genre'],
  validateFile: (filename, mimetype) => {
    return ['audio/mpeg', 'audio/wav', 'audio/ogg'].includes(mimetype)
  }
})

Dependencies

  • busboy (^1.6.0) - Multipart form data parsing

This is currently the only YAMF service module with external dependencies.

License

MIT