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

@ficsysfr/nestjs_module_factorydrive

v2.0.0

Published

Factory drive module for NestJS framework

Downloads

264

Readme

@ficsysfr/nestjs_module_factorydrive

nestjs_module_factorydrive provides a simple storage abstraction for NestJS:

  • configure one or many disks
  • select a default disk
  • use built-in local filesystem driver
  • register custom drivers (S3, Spaces, etc.)

Maintained Packages

Current maintained packages in the Factorydrive ecosystem:

Requirements

  • Node.js >= 22
  • Yarn 1.22.22 (used for development in this repository)
  • NestJS ^6 to ^11 (@nestjs/common and @nestjs/core)

Architecture and Portability

Application and business services should depend on FactorydriveService, not on a physical storage provider. Keep filesystem roots, buckets, endpoints, credentials, and driver selection in module configuration so the same business code can use local, S3, or SFTP storage.

Business service
      |
FactorydriveService
      |
AbstractStorage
  /      |      \
local    S3     SFTP

For application storage, avoid importing node:fs, S3Client, or an SFTP client into business services. Provider-specific SDKs belong inside Factorydrive drivers or narrowly justified infrastructure code.

Installation

yarn add @ficsysfr/nestjs_module_factorydrive

Or with another package manager:

npm install @ficsysfr/nestjs_module_factorydrive
pnpm add @ficsysfr/nestjs_module_factorydrive

Development

This repository uses Yarn, Vitest, TypeScript, and Biome:

yarn install --frozen-lockfile
yarn lint
yarn typecheck
yarn test
yarn test:coverage
yarn build
yarn mcp:test
yarn docs:build
yarn docs:check
yarn test:scripts
yarn changelog:check
yarn package:check

The equivalent aggregate command is make check. Build audited core and MCP tarballs with yarn package or make package; outputs and SHA256SUMS.txt are written under .artifacts/npm/.

Maintainers dispatch an exact manual release with make release VERSION=2.0.0 CHANNEL=latest WATCH=1. The privileged workflow uses the protected npm environment and npm Trusted Publishing/OIDC after the one-time bootstrap.

Quick Start (synchronous config)

// app.module.ts
import { Module } from '@nestjs/common'
import { FactorydriveModule } from '@ficsysfr/nestjs_module_factorydrive'

@Module({
  imports: [
    FactorydriveModule.forRoot({
      default: 'local',
      disks: {
        local: {
          driver: 'local',
          config: {
            root: `${process.cwd()}/storage`,
          },
        },
      },
    }),
  ],
})
export class AppModule {}

Async Configuration (forRootAsync)

// app.module.ts
import { Module } from '@nestjs/common'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { FactorydriveModule } from '@ficsysfr/nestjs_module_factorydrive'

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    FactorydriveModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (config: ConfigService) => ({
        default: config.get<string>('factorydrive.default', 'local'),
        disks: {
          local: {
            driver: 'local',
            config: {
              root: config.get<string>('factorydrive.localRoot', `${process.cwd()}/storage`),
            },
          },
        },
      }),
    }),
  ],
})
export class AppModule {}

Usage

Inject FactorydriveService and interact with a disk instance:

// file-storage.service.ts
import { Injectable } from '@nestjs/common'
import { FactorydriveService } from '@ficsysfr/nestjs_module_factorydrive'

@Injectable()
export class FileStorageService {
  public constructor(private readonly factorydrive: FactorydriveService) {}

  public async uploadFile(path: string, buffer: Buffer): Promise<void> {
    await this.factorydrive.getDisk().put(path, buffer)
  }

  public async readFile(path: string): Promise<string> {
    const { content } = await this.factorydrive.getDisk().get(path)
    return content
  }

  public async deleteFile(path: string): Promise<boolean | null> {
    const { wasDeleted } = await this.factorydrive.getDisk().delete(path)
    return wasDeleted
  }
}

If no disk name is provided, the configured default disk is used. Prefer this form so business code remains portable across storage providers:

const disk = this.factorydrive.getDisk()

Select a named disk only when the use case intentionally targets it:

const archive = this.factorydrive.getDisk('archive')

Built-in Local Driver

The package includes a local driver with the following operations:

  • append(location, content)
  • copy(src, dest)
  • delete(location)
  • exists(location)
  • get(location, encoding?)
  • getBuffer(location)
  • getStat(location)
  • getStream(location)
  • move(src, dest)
  • prepend(location, content)
  • put(location, content)
  • flatList(prefix?)
  • getUrl(location) — unsigned URL built from the disk baseUrl
  • getSignedUrl(location, { expiresIn? }) — time-limited HMAC-signed URL (default expiresIn = 900)
  • verifySignedUrl(location, { expires, signature }) — constant-time signature + expiry check

content for put accepts Buffer | ReadableStream | string.

Signed URLs (local)

The local driver has no HTTP server: getSignedUrl returns a URL pointing at a baseUrl endpoint that you expose and which must call verifySignedUrl before streaming the file. Configure the disk with a signatureSecret and a baseUrl:

disks: {
  local: {
    driver: 'local',
    config: {
      root: '/var/data',
      signatureSecret: process.env.STORAGE_URL_SECRET,
      baseUrl: 'https://api.example.com/files',
    },
  },
}

const { signedUrl } = await storage.getSignedUrl('threads/abc', { expiresIn: 3600 })
// -> https://api.example.com/files/threads/abc?expires=...&signature=...

// in the /files endpoint:
const ok = storage.verifySignedUrl('threads/abc', { expires, signature })

Both signatureSecret and baseUrl are required for signing; otherwise getSignedUrl throws InvalidConfigException.

Register a Custom Driver

Custom drivers must extend AbstractStorage and implement the methods you need.

// aws-s3.storage.ts
import { AbstractStorage, DeleteResponse, Response } from '@ficsysfr/nestjs_module_factorydrive'

export class AwsS3Storage extends AbstractStorage {
  public constructor(private readonly config: { bucket: string }) {
    super()
  }

  public async put(location: string, content: Buffer | NodeJS.ReadableStream | string): Promise<Response> {
    // Upload implementation...
    return { raw: { location, uploaded: true, contentType: typeof content } }
  }

  public async delete(location: string): Promise<DeleteResponse> {
    // Delete implementation...
    return { raw: { location }, wasDeleted: true }
  }
}

Then register it at startup:

// app.module.ts
import { Module, OnModuleInit } from '@nestjs/common'
import { FactorydriveModule, FactorydriveService } from '@ficsysfr/nestjs_module_factorydrive'
import { AwsS3Storage } from './aws-s3.storage'

@Module({
  imports: [
    FactorydriveModule.forRoot({
      default: 's3',
      disks: {
        s3: {
          driver: 's3',
          config: {
            bucket: 'example',
          },
        },
      },
    }),
  ],
})
export class AppModule implements OnModuleInit {
  public constructor(private readonly factorydrive: FactorydriveService) {}

  public onModuleInit(): void {
    this.factorydrive.registerDriver('s3', AwsS3Storage)
  }
}

Exported API

Main exports from this package:

  • FactorydriveModule
  • FactorydriveService
  • AbstractStorage
  • StorageManager
  • storage config/types from factorydrive/types
  • exceptions from exceptions

Error Handling

The module provides dedicated exceptions (for example):

  • InvalidConfigException
  • DriverNotSupportedException
  • FileNotFoundException
  • PermissionMissingException
  • MethodNotSupportedException

Catch and map them in your service/controller layers as needed.

AI Agent Skill

This repository includes an English use-factorydrive skill for Codex and compatible coding agents. It teaches agents to explain, configure, audit, and implement Factorydrive without coupling business code to a storage provider.

Example prompts:

Use $use-factorydrive to configure local document storage in this NestJS application.
Use $use-factorydrive to migrate this service from S3Client to FactorydriveService.
Use $use-factorydrive to expose a verified local signed-download endpoint.

Driver authors should use the separate factorydrive-driver skill.

Documentation for AI agents

The documentation MCP exposes list_doc_sources, search_docs, and fetch_docs over stdio. It never receives storage configuration and cannot read or mutate application files.

Migrating to 2.0

Version 2.0.0 moves the maintained ecosystem to the @ficsysfr npm scope without changing exported TypeScript symbols. Replace package names and import specifiers, then upgrade the core and every installed driver together. See the migration guide.

License

MIT