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 🙏

© 2025 – Pkg Stats / Ryan Hefner

universal_asset_mananger

v0.0.0

Published

A tiny orchestration layer for moving user uploads into a remote media provider (via [`universal_media_storage`](https://www.npmjs.com/package/universal_media_storage)) while persisting the final asset metadata to your own database. It is framework‑agno

Readme

Universal Asset Manager

A tiny orchestration layer for moving user uploads into a remote media provider (via universal_media_storage) while persisting the final asset metadata to your own database.
It is framework‑agnostic, works perfectly with express-fileupload, and only asks you to supply an IAssetDatabase implementation.

Highlights

  • Storage + DB in sync – upload files to Firebase Storage (or any other MediaStorage driver) and immediately save canonical asset metadata such as URLs, hashes, and sizes.
  • Duplicate protectionAssetUploader checks your DB via doesAssetPathAlreadyExist before streaming the file, preventing wasted bandwidth.
  • Relative-path aware bulk uploadsuploadMultipleAssetsToMediaStorageAndDB keeps folder structures intact (great for ZIP/unpacked directory uploads).
  • Storage-only migrationsuploadMultipleFilesToMediaStorageOnly lets you seed or mirror remote storage without touching the DB layer.
  • Folder analytics – Keep lightweight per-folder counts and sizes through getFolderSummary / addFolderStats.
  • Fully typed – Ships Asset, UploadObject, ResultSummary, and FileWithPath helpers so TypeScript consumers stay safe.

Installation

npm install universal_asset_mananger
# peerdep used internally for uploads
npm install universal_media_storage

The package is written in TypeScript and publishes types out of the box—no extra typings are required.


Quick start

  1. Implement the persistence contract
    import { Asset, IAssetDatabase } from "universal_asset_mananger";
    
    class AssetRepository implements IAssetDatabase {
      async saveToDatabase({ assets }: { assets: Asset[] }) {
        // batch insert into your table/collection
      }
    
      async doesAssetPathAlreadyExist(path: string) {
        // return true if path already present
      }
    }
  2. Configure your storage backend – the example uses Firebase Storage through the MediaStorage abstraction:
    import { FirebaseStorageService, MediaStorage } from "universal_media_storage";
    
    const storage = new MediaStorage({
      config: {
        firebase_service_account_key_base64: process.env.FIREBASE_SERVICE_ACCOUNT_BASE64 ?? "",
        firebase_storage_bucket: process.env.FIREBASE_STORAGE_BUCKET ?? "",
      },
      service: new FirebaseStorageService(),
    });
  3. Instantiate the uploader and send files
    import AssetUploader from "universal_asset_mananger/dist/services/AssetUploader";
    import { FileWithPath } from "universal_asset_mananger";
    
    const uploader = new AssetUploader(new AssetRepository(), storage);
    
    const files: FileWithPath[] = [
      {
        name: "example.txt",
        relativePath: "folder1/example.txt",
        data: Buffer.from("Hello!"),
        mimetype: "text/plain",
        mv: () => Promise.resolve(),
        encoding: "utf-8",
        truncated: false,
        size: 6,
        tempFilePath: "",
        md5: "",
      },
    ];
    
    await uploader.uploadMultipleAssetsToMediaStorageAndDB({
      uploadedFiles: files,
      basePath: "assets",
    });

📁 A working script lives in example/index.ts. Run it with:

cd example
npm install
FIREBASE_SERVICE_ACCOUNT_BASE64=... FIREBASE_STORAGE_BUCKET=... npm start

Operations

| Method | Purpose | Notable parameters | | --- | --- | --- | | uploadSingleAssetToMediaStorageAndDB(uploadObject) | Uploads one file, writes its metadata to the DB, updates resultSummary, and tracks folder stats. | assetFolderName, relativePath, mimetype, fileData, optional parentPathIds for nested remote folders. | | uploadMultipleAssetsToMediaStorageAndDB({ uploadedFiles, basePath, resultSummary }) | Accepts a single file or a collection (like from express-fileupload), resolves MIME types via mime-types, and delegates each file to the single-upload flow with duplicate protection. | basePath becomes the top-level remote folder; resultSummary lets you collect URLs & sizes for downstream reporting. | | uploadMultipleFilesToMediaStorageOnly({ files, basePath, remoteParentPaths }) | Sends files to storage without touching your database—ideal for migrations, replays, or one-off batches. Returns a ResultSummary map internally. | remoteParentPaths forwards any provider-specific folder hierarchy identifiers. | | getFolderSummary() | Returns the internal Map<string, FolderStats> so you can report folder counts/sizes after a job completes. | — | | addFolderStats(folderPath, stats) | Manually seed or merge folder summaries when combining batches. | stats should match { count: number; size: number; }. |

All operations lean on the shared FileWithPath shape (a superset of express-fileupload’s UploadedFile) so you can pipe files straight from API routes.


Types and interfaces

  • Asset: canonical record saved to your DB (id, storage URL, hash, size, encoded path, etc.).
  • UploadObject: internal shape for single upload orchestration.
  • ResultSummary: { [relativePath: string]: { url: string; size: number } } for quick reporting.
  • FileWithPath: extends express-fileupload’s UploadedFile with an optional relativePath.
  • IAssetDatabase: the only contract you must implement—saveToDatabase and doesAssetPathAlreadyExist.

These types can be imported from the package root.


Development

npm install
npm run example   # transpile and execute example/index.ts via ts-node

The project uses TypeScript, ESLint, and Prettier (see configs at the repo root). Contribution ideas include adding more storage providers, extending folder analytics, or providing adapters for popular ORMs.


License

MIT © Olamide Ogunlade