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

@bernierllc/content-type-video

v1.2.0

Published

Base video content type with file upload, local storage, and streaming URL generation

Readme

@bernierllc/content-type-video

Base video content type with file upload, local storage, and streaming URL generation for the BernierLLC Content Management Suite.

Installation

npm install @bernierllc/content-type-video

Features

  • Video File Upload - Upload video files with validation (format, size)
  • Local File Storage - Store videos in local file system with automatic directory creation
  • Metadata Extraction - Extract video metadata (duration, dimensions, fps, codec)
  • Streaming URL Generation - Generate streaming URLs for uploaded videos
  • Configurable - Environment variables and constructor options
  • TypeScript - Full type safety with strict mode
  • Well Tested - 100% statements, functions, and lines coverage

Usage

Basic Usage

import { VideoContentType } from '@bernierllc/content-type-video';

// Create instance with defaults
const videoType = new VideoContentType();

// Upload a video file
const result = await videoType.upload(
  videoBuffer,  // Buffer or file path
  'my-video.mp4',
  'user-123'    // Optional: uploaded by
);

if (result.success) {
  console.log('Video uploaded!');
  console.log('File path:', result.data?.filePath);
  console.log('Streaming URL:', result.data?.streamingUrl);
  console.log('Metadata:', result.data?.metadata);
}

Custom Configuration

const videoType = new VideoContentType({
  baseType: 'video',
  editor: 'file-upload-with-player',
  storage: 'file',
  publishing: 'streaming-url',
  uploadOptions: {
    maxSizeBytes: 1024 * 1024 * 1024, // 1GB
    allowedFormats: ['mp4', 'webm'],
    generateThumbnail: true,
    extractMetadata: true,
    storageBasePath: './custom-storage/videos'
  },
  streamingBaseUrl: '/cdn/video/stream'
});

Environment Variables

VIDEO_MAX_SIZE_BYTES=524288000           # Maximum file size (500MB default)
VIDEO_ALLOWED_FORMATS=mp4,webm,mov,avi  # Comma-separated allowed formats
VIDEO_GENERATE_THUMBNAIL=true            # Generate thumbnail on upload
VIDEO_EXTRACT_METADATA=true              # Extract metadata on upload
VIDEO_STORAGE_BASE_PATH=./storage/videos # Base path for video file storage
VIDEO_STREAMING_BASE_URL=/api/video/stream # Base URL for streaming endpoint

API Reference

VideoContentType

Main class for video content type operations.

Constructor

constructor(config?: Partial<VideoContentTypeConfig>)

Methods

upload(file, filename, uploadedBy?)

Upload a video file and extract metadata.

async upload(
  file: Buffer | string,
  filename: string,
  uploadedBy?: string
): Promise<VideoContentResult<VideoContentData>>

Parameters:

  • file: Buffer or file path to the video file
  • filename: Original filename (used for extension detection)
  • uploadedBy: Optional user identifier who uploaded the video

Returns: Result object with uploaded video data or error

validate(file, filename)

Validate video file before upload.

async validate(
  file: Buffer | string,
  filename: string
): Promise<VideoContentResult<void>>
get(localPath)

Retrieve video file from storage.

async get(localPath: string): Promise<Buffer | null>
delete(localPath)

Delete video file from storage.

async delete(localPath: string): Promise<boolean>
exists(localPath)

Check if video file exists in storage.

async exists(localPath: string): Promise<boolean>
getStreamingUrl(localPath)

Generate streaming URL for video file.

getStreamingUrl(localPath: string): string
validateContent(data)

Validate video content data structure.

validateContent(data: VideoContentData): VideoContentResult<VideoContentData>
register()

Register video content type with content type registry.

async register(): Promise<void>

Type Definitions

VideoMetadata

interface VideoMetadata {
  filename: string;
  mimeType: string;          // e.g., 'video/mp4'
  size: number;              // File size in bytes
  duration: number;          // Duration in seconds
  width: number;             // Video width in pixels
  height: number;            // Video height in pixels
  fps: number;               // Frames per second
  thumbnail?: string;        // Optional thumbnail URL
  bitrate?: number;          // Optional bitrate
  codec?: string;            // Optional codec information
}

VideoContentData

interface VideoContentData {
  filePath: string;          // Local file path
  streamingUrl: string;      // Generated streaming URL
  metadata: VideoMetadata;   // Video metadata
  uploadedAt: Date;          // Upload timestamp
  uploadedBy?: string;       // Optional uploader identifier
}

VideoUploadOptions

interface VideoUploadOptions {
  maxSizeBytes?: number;          // Default: 500MB
  allowedFormats?: string[];      // Default: ['mp4', 'webm', 'mov', 'avi']
  generateThumbnail?: boolean;    // Default: true
  extractMetadata?: boolean;      // Default: true
  storageBasePath?: string;       // Default: './storage/videos'
}

Examples

Upload from Buffer

import fs from 'fs';
import { VideoContentType } from '@bernierllc/content-type-video';

const videoType = new VideoContentType();
const videoBuffer = fs.readFileSync('./my-video.mp4');

const result = await videoType.upload(videoBuffer, 'my-video.mp4');

if (result.success) {
  console.log('Upload successful!');
  console.log(`Streaming URL: ${result.data?.streamingUrl}`);
  console.log(`Duration: ${result.data?.metadata.duration}s`);
  console.log(`Resolution: ${result.data?.metadata.width}x${result.data?.metadata.height}`);
}

Upload from File Path

const result = await videoType.upload('/path/to/video.mp4', 'video.mp4', 'user-123');

Validate Video Format

const result = await videoType.upload(buffer, 'video.avi');

if (!result.success) {
  console.error('Upload failed:', result.error);
  // Error: File format avi not allowed. Allowed: mp4, webm, mov, avi
}

Custom Storage Location

const videoType = new VideoContentType({
  uploadOptions: {
    storageBasePath: '/data/videos'
  }
});

Delete Uploaded Video

const uploadResult = await videoType.upload(buffer, 'video.mp4');

if (uploadResult.success && uploadResult.data) {
  const filePath = uploadResult.data.filePath;

  // Later, delete the video
  const deleted = await videoType.delete(filePath);

  if (deleted) {
    console.log('Video deleted successfully');
  }
}

Integration

Logger Integration

  • Status: planned
  • Usage: Log upload operations, metadata extraction, and errors

NeverHub Integration

  • Status: optional
  • Events Published:
    • video.uploaded - When video file is successfully uploaded
    • video.metadata-extracted - When metadata extraction completes
    • video.validation-failed - When video validation fails

Docs-Suite Compatibility

  • Status: ready
  • Format: typedoc
  • Documentation: Complete API documentation with TypeScript types

Platform-Specific Extensions

This base package is designed to be extended for platform-specific video content types:

  • @bernierllc/content-type-youtube - YouTube video integration
  • @bernierllc/content-type-tiktok - TikTok video integration
  • @bernierllc/content-type-instagram-reels - Instagram Reels integration

Dependencies

  • @bernierllc/content-type-registry (^1.0.3) - Content type registration
  • zod (^3.22.0) - Schema validation

Development

# Install dependencies
npm install

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Build package
npm run build

# Lint code
npm run lint

Quality Metrics

  • Test Coverage: 98.86% statements, 100% functions, 98.86% lines, 79.31% branches
  • Tests: 37 passing, 0 failing (100% pass rate)
  • TypeScript: Strict mode enabled, zero errors
  • Linting: Zero errors or warnings
  • Build: Successful compilation

License

Copyright (c) 2025 Bernier LLC

This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.

Related Packages

Part of Suite

Contributing

This package is part of the BernierLLC monorepo and follows strict quality standards:

  • 90%+ test coverage (all metrics)
  • 100% test pass rate
  • TypeScript strict mode
  • Zero linting errors
  • License headers in all files

For more information, see CLAUDE.md in the repository root.