CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-medusa-interfaces

Core interfaces for Medusa e-commerce framework service implementations

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

file-service.mddocs/

File Service

Interface for file storage service implementations providing upload and delete operations for handling file assets across different storage providers.

Deprecation Notice: Use AbstractFileService from @medusajs/medusa instead.

Capabilities

Static Methods

Type checking and identification methods for file services.

/**
 * Static property identifying this as a file service
 */
static _isFileService: boolean;

/**
 * Checks if an object is a file service
 * @param {object} obj - Object to check
 * @returns {boolean} True if obj is a file service
 */
static isFileService(obj: object): boolean;

Core File Operations

Abstract methods that must be implemented by child classes for file storage operations.

/**
 * Uploads files to the storage provider
 * @returns {any} Upload result
 * @throws {Error} If not overridden by child class
 */
upload(): any;

/**
 * Deletes files from the storage provider
 * @returns {any} Deletion result
 * @throws {Error} If not overridden by child class
 */
delete(): any;

Implementation Example

import { FileService } from "medusa-interfaces";
import fs from "fs";
import path from "path";

class LocalFileService extends FileService {
  constructor(options) {
    super();
    this.uploadDir = options.upload_dir || "./uploads";
    this.baseUrl = options.base_url || "http://localhost:9000";
  }

  async upload(files) {
    const uploadedFiles = [];
    
    // Handle single file or array of files
    const fileArray = Array.isArray(files) ? files : [files];
    
    for (const file of fileArray) {
      // Generate unique filename
      const filename = `${Date.now()}-${file.originalname}`;
      const filepath = path.join(this.uploadDir, filename);
      
      // Ensure upload directory exists
      if (!fs.existsSync(this.uploadDir)) {
        fs.mkdirSync(this.uploadDir, { recursive: true });
      }
      
      // Write file to disk
      fs.writeFileSync(filepath, file.buffer);
      
      uploadedFiles.push({
        url: `${this.baseUrl}/uploads/${filename}`,
        key: filename,
        originalname: file.originalname,
        size: file.size,
        mimetype: file.mimetype
      });
    }
    
    return uploadedFiles.length === 1 ? uploadedFiles[0] : uploadedFiles;
  }

  async delete(fileKey) {
    try {
      const filepath = path.join(this.uploadDir, fileKey);
      
      if (fs.existsSync(filepath)) {
        fs.unlinkSync(filepath);
        return { success: true, key: fileKey };
      } else {
        throw new Error(`File not found: ${fileKey}`);
      }
    } catch (error) {
      throw new Error(`Failed to delete file: ${error.message}`);
    }
  }
}

// AWS S3 implementation example
class S3FileService extends FileService {
  constructor(options) {
    super();
    this.s3Client = new AWS.S3({
      accessKeyId: options.access_key_id,
      secretAccessKey: options.secret_access_key,
      region: options.region
    });
    this.bucket = options.bucket;
  }

  async upload(files) {
    const uploadedFiles = [];
    const fileArray = Array.isArray(files) ? files : [files];
    
    for (const file of fileArray) {
      const key = `${Date.now()}-${file.originalname}`;
      
      const uploadParams = {
        Bucket: this.bucket,
        Key: key,
        Body: file.buffer,
        ContentType: file.mimetype,
        ACL: 'public-read'
      };
      
      const result = await this.s3Client.upload(uploadParams).promise();
      
      uploadedFiles.push({
        url: result.Location,
        key: result.Key,
        originalname: file.originalname,
        size: file.size,
        mimetype: file.mimetype
      });
    }
    
    return uploadedFiles.length === 1 ? uploadedFiles[0] : uploadedFiles;
  }

  async delete(fileKey) {
    try {
      const deleteParams = {
        Bucket: this.bucket,
        Key: fileKey
      };
      
      await this.s3Client.deleteObject(deleteParams).promise();
      return { success: true, key: fileKey };
    } catch (error) {
      throw new Error(`Failed to delete file from S3: ${error.message}`);
    }
  }
}

Usage in Medusa

File services are typically used in Medusa for:

  • Product Images: Uploading and managing product photos
  • User Avatars: Profile picture management
  • Document Storage: Invoices, receipts, and other documents
  • Media Assets: General file asset management

Basic Usage Pattern:

// In a Medusa service or API route
class ProductService {
  constructor({ fileService }) {
    this.fileService_ = fileService;
  }

  async uploadProductImages(productId, imageFiles) {
    // Upload images using the file service
    const uploadedImages = await this.fileService_.upload(imageFiles);
    
    // Store image URLs in product record
    await this.updateProduct(productId, {
      images: uploadedImages.map(img => img.url)
    });
    
    return uploadedImages;
  }

  async deleteProductImage(imageKey) {
    // Delete image file
    await this.fileService_.delete(imageKey);
    
    // Remove from product record
    // ... update logic
  }
}

Error Handling

Both abstract methods throw descriptive errors when not implemented:

  • "upload must be overridden by the child class"
  • "delete must be overridden by the child class"

Common Implementation Patterns

File Upload Parameters

Most implementations expect file objects with these properties:

{
  originalname: string,  // Original filename
  buffer: Buffer,        // File data
  mimetype: string,      // MIME type
  size: number          // File size in bytes
}

Return Value Patterns

Upload operations typically return:

{
  url: string,          // Public URL to access the file
  key: string,          // Storage identifier/key
  originalname: string, // Original filename
  size: number,         // File size
  mimetype: string      // MIME type
}

Delete operations typically return:

{
  success: boolean,     // Operation success status
  key: string          // Key of deleted file
}

docs

base-service.md

file-service.md

fulfillment-service.md

index.md

notification-service.md

oauth-service.md

payment-service.md

search-service.md

tile.json