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

@flusys/ng-storage

v4.1.1

Published

File storage module for FLUSYS Angular applications

Readme

@flusys/ng-storage

File storage UI library for the FLUSYS Angular platform — file upload, folder management, file browser, presigned URL fetching, and provider adapter registration.

npm version Angular TypeScript License: MIT


Table of Contents


Overview

@flusys/ng-storage provides the complete file management UI for FLUSYS applications. It supports all four storage backends (Local, S3, Azure Blob, SFTP) transparently — the backend generates the correct presigned URLs for each provider.

Critical rule: Never construct file URLs manually. Always use FileUrlService (from ng-shared) or the FILE_PROVIDER token. The backend generates presigned URLs that are provider-agnostic and access-controlled.


Features

  • ✅ File browser with folder navigation
  • ✅ Drag-and-drop upload with progress
  • ✅ Multi-file selection dialog (FileSelectorDialogComponent)
  • ✅ Image preview thumbnails
  • ✅ Download and delete actions
  • UploadService — typed multi-part file upload
  • provideStorageProviders() — registers FILE_PROVIDER for shared components
  • ✅ Presigned URL fetching via FileUrlService
  • ✅ Support for LOCAL, S3, AZURE, SFTP backends

Compatibility

| Package | Version | |---------|---------| | Angular | 21+ | | @flusys/ng-core | 4.x | | @flusys/ng-shared | 4.x |


Installation

npm install @flusys/ng-storage @flusys/ng-core @flusys/ng-shared

Quick Start

1. Enable Storage in Config

// environments/environment.ts
export const environment = {
  services: {
    storage: { enabled: true },
  },
};

2. Register Storage Providers

// app.config.ts
import { provideStorageProviders } from '@flusys/ng-storage';

export const appConfig: ApplicationConfig = {
  providers: [
    ...provideStorageProviders(),
    // Provides: FILE_PROVIDER (IFileProvider) — used by FileSelectorDialogComponent, FileUrlService
  ],
};

3. Add Storage Routes (Optional)

// app.routes.ts
import { STORAGE_ROUTES } from '@flusys/ng-storage';

export const routes: Routes = [
  {
    path: 'storage',
    loadChildren: () => STORAGE_ROUTES,
  },
];

Module Registration

provideStorageProviders()

Registers the storage adapter against the FILE_PROVIDER token from ng-shared:

import { provideStorageProviders } from '@flusys/ng-storage';

providers: [
  ...provideStorageProviders(),
]

This enables:

  • FileSelectorDialogComponent (from ng-shared) to list/browse files
  • FileUrlService.fetchSingleFileUrl() to work correctly
  • HasPermissionDirective to show storage-gated content

File URL Rule

CRITICAL: Never construct file URLs manually. The backend handles URL generation for all storage providers (Local, S3, Azure, SFTP) including presigned URL rotation.

// ❌ WRONG — breaks with S3, Azure, SFTP
const url = `${apiBaseUrl}/uploads/${fileId}`;
const url = `https://my-bucket.s3.amazonaws.com/${path}`;

// ✅ CORRECT — always use FileUrlService
import { FileUrlService } from '@flusys/ng-shared';

const file = await this.fileUrlService.fetchSingleFileUrl(fileId);
const url = file?.url ?? null; // Presigned, access-controlled, provider-agnostic

Why backend URLs:

  • S3/Azure require presigned URLs that expire
  • URLs are access-controlled (user must have permission)
  • Works transparently across all 4 storage providers
  • Automatic URL refresh on expiry

Services

FileManagerApiService

Typed API client for file management operations:

import { FileManagerApiService } from '@flusys/ng-storage';

@Injectable({ ... })
export class MyService {
  private fileApi = inject(FileManagerApiService);

  getFiles(folderId?: string): Observable<IListResponse<IFile>> {
    return this.fileApi.getAll({ filters: { folderId } });
  }

  getFileUrls(fileIds: string[]): Observable<ISingleResponse<IFileWithUrl[]>> {
    return this.fileApi.getFiles(fileIds);
  }

  deleteFile(id: string): Observable<IMessageResponse> {
    return this.fileApi.delete(id);
  }
}

FileManagerApiService Methods:

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(params) | POST /file-manager/get-all | List files with pagination | | getById(id) | POST /file-manager/get/:id | Get file metadata | | getFiles(ids[]) | POST /file-manager/get-files | Batch fetch with presigned URLs | | delete(id) | POST /file-manager/delete | Delete file | | bulkDelete(ids[]) | POST /file-manager/bulk-delete | Delete multiple files | | move(id, folderId) | POST /file-manager/move | Move file to folder |

FolderApiService

Typed API client for folder management:

import { FolderApiService } from '@flusys/ng-storage';

@Injectable({ ... })
export class MyService {
  private folderApi = inject(FolderApiService);

  getFolders(parentId?: string): Observable<IListResponse<IFolder>> {
    return this.folderApi.getAll({ filters: { parentId } });
  }

  createFolder(name: string, parentId?: string): Observable<ISingleResponse<IFolder>> {
    return this.folderApi.insert({ name, parentId });
  }
}

FolderApiService Methods:

| Method | Endpoint | Description | |--------|----------|-------------| | getAll(params) | POST /folder/get-all | List folders | | getById(id) | POST /folder/get/:id | Get folder | | insert(dto) | POST /folder/insert | Create folder | | update(dto) | POST /folder/update | Rename folder | | delete(id) | POST /folder/delete | Delete folder |

UploadService

Handles multi-part file uploads with progress tracking:

import { UploadService } from '@flusys/ng-storage';

@Component({ ... })
export class UploadComponent {
  private uploadService = inject(UploadService);

  uploadFile(file: File, folderId?: string): void {
    this.uploadService.upload(file, { folderId }).subscribe({
      next: (event) => {
        if (event.type === 'progress') {
          console.log(`Progress: ${event.percent}%`);
        }
        if (event.type === 'complete') {
          console.log('Uploaded:', event.file);
        }
      },
      error: (err) => console.error('Upload failed:', err),
    });
  }

  uploadMultiple(files: File[]): void {
    this.uploadService.uploadBatch(files).subscribe(results => {
      console.log(`Uploaded ${results.length} files`);
    });
  }
}

UploadService API:

| Method | Description | |--------|-------------| | upload(file, options?) | Single file upload with progress events | | uploadBatch(files, options?) | Multiple file upload (sequential) | | cancel(uploadId) | Cancel in-progress upload |


Components

FileManagerComponent

Full-page file browser with folder tree, grid/list view, upload, and actions.

<!-- Full file manager -->
<flusys-file-manager />

<!-- With pre-selected folder -->
<flusys-file-manager [initialFolderId]="rootFolderId" />

Features:

  • Folder tree (left panel)
  • File grid with thumbnails (right panel)
  • Drag-and-drop upload zone
  • Right-click context menu (rename, move, delete)
  • Breadcrumb navigation
  • Search files

FileSelectorDialogComponent

Dialog for selecting one or multiple files. Used by other packages (ng-form-builder, ng-email) to pick files.

<flusys-file-selector-dialog
  [visible]="showPicker"
  [multiple]="true"
  [accept]="'image/*'"
  (fileSelected)="onFilesSelected($event)"
  (cancel)="showPicker = false"
/>

| Input | Type | Description | |-------|------|-------------| | visible | boolean | Show/hide dialog | | multiple | boolean | Allow multi-select (default: false) | | accept | string | MIME type filter | | folderId | string | Pre-open specific folder |

| Output | Type | Description | |--------|------|-------------| | fileSelected | IFile \| IFile[] | Selected file(s) | | cancel | void | Dialog dismissed |

FileUploaderComponent

Lightweight standalone upload component (without the full browser):

<flusys-file-uploader
  [multiple]="false"
  [accept]="'image/jpeg,image/png'"
  [maxSizeMb]="5"
  [folderId]="profilePicturesFolderId"
  (uploaded)="onAvatarUploaded($event)"
/>

Storage Routes

Lazy-loaded pages for the full file manager:

import { STORAGE_ROUTES } from '@flusys/ng-storage';

{ path: 'storage', loadChildren: () => STORAGE_ROUTES }

| Route | Component | Description | |-------|-----------|-------------| | /storage | FileManagerPageComponent | Full file manager page | | /storage/folder/:id | FileManagerPageComponent | Open specific folder |


File Location Enum

import { FileLocationEnum } from '@flusys/ng-storage';

enum FileLocationEnum {
  LOCAL = 'LOCAL',
  S3 = 'S3',
  AZURE = 'AZURE',
  SFTP = 'SFTP',
}

Use FileLocationEnum when filtering or categorizing files by their storage backend.


API Endpoints

| Method | Endpoint | Description | |--------|----------|-------------| | POST | /file-manager/get-all | List files with pagination | | POST | /file-manager/get/:id | Get file metadata | | POST | /file-manager/get-files | Batch fetch with presigned URLs | | POST | /file-manager/upload | Upload file (multipart) | | POST | /file-manager/delete | Delete file | | POST | /file-manager/bulk-delete | Delete multiple files | | POST | /file-manager/move | Move file to folder | | POST | /folder/get-all | List folders | | POST | /folder/get/:id | Get folder metadata | | POST | /folder/insert | Create folder | | POST | /folder/update | Rename folder | | POST | /folder/delete | Delete folder |


Configuration Reference

| Config Key | Type | Default | Description | |------------|------|---------|-------------| | services.storage.enabled | boolean | false | Enable storage module |

The storage backend (LOCAL/S3/AZURE/SFTP) is configured server-side in nestjs-storage. The Angular client doesn't need to know which provider is active.


Troubleshooting

File thumbnails don't load

Images are loaded via presigned URLs. Ensure FileUrlService.fetchSingleFileUrl() is used (not manual URL construction). Check the browser network tab — are the URLs returning 403?

Upload fails with 413 Payload Too Large

The backend has a file size limit. Configure maxBodySize in nestjs-storage on the server. On the Angular side, validate client-side before upload:

<flusys-file-uploader [maxSizeMb]="10" />

No provider for FILE_PROVIDER

Add provideStorageProviders() to app.config.ts providers.

FileSelectorDialog is empty (no files)

Ensure the user has permission to list files (file:read) and the backend storage is configured. Check the network tab for errors on POST /file-manager/get-all.

Files visible but download fails

The presigned URL may have expired. Call FileUrlService.clearCache(fileId) to force a fresh URL fetch.


License

MIT © FLUSYS