JCC Express

Digging Deeper

File Storage

Introduction

JCC Express MVC includes a Laravel-like storage layer with a StorageManager and pluggable disk drivers.

The built-in export is:

  • Storage (singleton manager with default config)
  • StorageManager (create your own configured manager)
  • LocalDriver (filesystem driver)
  • StorageUtils (path/mime helper utilities)

Import and basic usage

TypeScript
import { Storage } from "jcc-express-mvc/Core/Storage";

await Storage.put("notes/readme.txt", "Hello");
const content = await Storage.get("notes/readme.txt");
const exists = await Storage.exists("notes/readme.txt");

Available methods

On the manager (default disk):

  • exists(path)
  • get(path)
  • put(path, contents)
  • putFile(path, buffer)
  • delete(path)
  • files(directory?)
  • allFiles(directory?)
  • directories(directory?)
  • makeDirectory(path)
  • size(path)
  • copy(from, to)
  • move(from, to)
  • url(path)

On a disk driver (Storage.disk("name")), you also get:

  • deleteDirectory(directory)
  • lastModified(path)
  • temporaryUrl(path, expiration)

Working with disks

Pick a specific disk with disk(name):

TypeScript
const publicDisk = Storage.disk("public");
await publicDisk.put("avatars/a1.txt", "avatar metadata");
const link = publicDisk.url("avatars/a1.txt");

Default behavior uses the configured default disk (local in the shipped config).


Default configuration

The shipped storage config includes:

  • local -> ./storage/app
  • public -> ./storage/app/public with URL /storage

Example default shape:

TypeScript
export const defaultConfig = {
  default: "local",
  disks: {
    local: { driver: "local", root: "./storage/app" },
    public: {
      driver: "local",
      root: "./storage/app/public",
      url: "/storage",
      visibility: "public",
    },
  },
};

Create your own manager

If you want custom disks or roots, instantiate StorageManager directly:

TypeScript
import { StorageManager } from "jcc-express-mvc/Core/Storage";

const storage = new StorageManager({
  default: "local",
  disks: {
    local: { driver: "local", root: "/var/app/storage" },
  },
});

HTTP request uploads (req.file / req.store)

For multipart form uploads handled by express-fileupload, use the request helpers instead of Storage directly:

TypeScript
const fileName = req.file("avatar").store("uploads/avatars");
const url = await req.storeToCloudinary("image", { folder: "avatars" });

See Request for the full file + store chain, return types (string | string[]), and Cloudinary options.


Upload helpers

StorageUtils includes helper methods:

  • generatePath(filename, directory?)
  • storeUploadedFile(storageDriver, fileBuffer, filename, directory?)
  • getMimeType(filename)

Example:

TypeScript
import { Storage, StorageUtils } from "jcc-express-mvc/Core/Storage";

const filePath = await StorageUtils.storeUploadedFile(
  Storage.disk("public"),
  fileBuffer,
  "invoice.pdf",
  "invoices",
);

Notes

  • Local driver url(...) returns a file:// URL for resolved path.
  • temporaryUrl(...) currently returns regular local URL (no signed URL behavior yet).
  • Missing files are handled safely (get -> null, exists -> false, etc.).

Summary

  • Use Storage for quick default-disk operations.
  • Use Storage.disk("public") for per-disk targeting.
  • Use StorageManager for custom configuration.
  • Use StorageUtils to standardize upload paths and mime handling.