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

thru-mft-webcomponents

v0.1.17

Published

A collection of web components for file upload functionality, built with Preact and TypeScript. These components provide a robust, resumable file upload experience with progress tracking, error handling, and more.

Readme

Thru MFT Web Components

A collection of web components for file upload functionality, built with Preact and TypeScript. These components provide a robust, resumable file upload experience with progress tracking, error handling, and more.

Features

  • Resumable File Uploads: Automatically resume interrupted uploads
  • Chunked File Transfers: Files are split into chunks for efficient uploading
  • Progress Tracking: Real-time upload progress with speed and time estimations
  • Drag-and-Drop Support: User-friendly file selection interface
  • Conflict Resolution: Handles file conflicts with options to resume or overwrite
  • Auto-Upload: Configure whether uploads start automatically
  • Error Handling: Comprehensive error reporting and recovery options
  • Upload Cancellation: Ability to cancel uploads in progress
  • Upload Interceptor: Modify upload context before an upload begins
  • Multiple File Uploads: Support for uploading multiple files simultaneously
  • Server Path Selection: Choose from available server paths or automatically use the first one
  • Customizable Retry Logic: Configure retry attempts and delays for failed uploads

Installation

CDN Usage

Add the following to your HTML:

<script type="module" src="https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.css" />

NPM Installation

npm install thru-mft-webcomponents
# or
yarn add thru-mft-webcomponents
# or
pnpm add thru-mft-webcomponents

Usage

Thru Upload Web Component

The thru-upload web component provides resumable file upload functionality with progress tracking and error handling.

<thru-upload
  api-key="your-api-key"
  flow-endpoint-id="123"
  api-url="https://your-api-url.com/api"
  auto-upload="true"
  assume-first-server-path="false"
  min-retry-delay="1000"
  retry-attempts="3"
></thru-upload>

Attributes

| Attribute | Type | Required | Default | Description | | -------------------------- | ------- | -------- | ------- | ------------------------------------------------------------- | | api-key | string | Yes | - | Your API key for authentication | | flow-endpoint-id | number | Yes | - | ID of the flow endpoint to upload to | | api-url | string | Yes | - | Base URL of your API | | auto-upload | boolean | No | true | Whether to start upload automatically when files are selected | | assume-first-server-path | boolean | No | false | Whether to automatically use the first available server path | | min-retry-delay | number | No | - | Minimum delay between retry attempts in milliseconds | | retry-attempts | number | No | - | Maximum number of retry attempts for failed uploads |

Events

The component dispatches the following custom events:

  • thru-upload-completed: Fired when an upload is completed successfully

    window.addEventListener("thru-upload-completed", (e) => {
      console.log(e.detail) // Contains upload details including id and uploadContext
    })
  • upload-files-added: Fired when files are added to the upload queue

    window.addEventListener("upload-files-added", (e) => {
      console.log(e.detail.files) // Contains file details
    })

Methods

The component exposes the following methods:

  • triggerUploads(): Manually trigger the upload of selected files
    const uploadedFiles = await document.querySelector("thru-upload").triggerUploads()

Upload Interceptor

You can add an upload interceptor to modify the upload context before the upload begins:

const thruUploadElement = document.querySelector("thru-upload")
thruUploadElement.uploadInterceptor = async (context) => {
  // Modify context as needed
  context.filePath = "custom/path"
  return context
}

Resume Upload Logic

The component automatically handles resuming uploads in case of interruptions:

  1. Upload sessions are saved in localStorage with key upload-session-{flowEndpointId}-{fileName}-{fileSize}
  2. When the component is initialized, it checks for existing upload sessions
  3. For incomplete uploads, it presents options to resume or restart the upload
  4. When resuming, it retrieves the last uploaded chunk from the server and continues from there

Upload Lifecycle

The upload process follows these states:

  1. Initial: Upload is being prepared
  2. Waiting: Ready to start upload
  3. In-progress: Upload is ongoing, showing progress, speed, and time remaining
  4. Assembling: All chunks uploaded, server is assembling the file
  5. Completed: Upload successfully completed
  6. Error: Error occurred during upload (with retry option)

FileUpload Component (React/Preact)

The FileUpload component provides a resumable file upload functionality with progress tracking and error handling.

import { FileUpload } from "thru-mft-webcomponents"

// In your component:
<FileUpload
  id="unique-upload-id"
  fileToUpload={file}
  abortController={new AbortController()}
  initialUploadContext={{
    flowEndpointId: number,
    serverPath: string,
    fileName: string,
    fileSize: number,
    filePath: string
  }}
  updateState={(updatedFile) => {
    // Handle state updates
  }}
  autoUpload={true}
  retryDelayMs={1000} // Optional
  retryAttempts={3} // Optional
/>

Props

| Prop | Type | Required | Description | | ---------------------- | ---------------------- | -------- | -------------------------------------------- | | id | string | Yes | Unique identifier for the upload | | fileToUpload | File | Yes | The file to be uploaded | | abortController | AbortController | Yes | Controller for handling upload cancellation | | initialUploadContext | ResumableUploadContext | Yes | Initial context for the upload | | updateState | (file: any) => void | Yes | Callback for state updates | | autoUpload | boolean | Yes | Whether to start upload automatically | | retryDelayMs | number | No | Delay between retry attempts in milliseconds | | retryAttempts | number | No | Maximum number of retry attempts |

UploadModal Component (React/Preact)

The UploadModal component provides a modal interface for file uploads with drag-and-drop support.

import { UploadModal } from "thru-mft-webcomponents"

// In your component:
<UploadModal
  selectedFlowEndpointId={123}
  flowEnabled={true}
  getUploadInterceptor={() => {
    // Return your interceptor function
  }}
  autoUpload={true}
  assumeFirstServerPath={true}
  retryDelayMs={1000} // Optional
  retryAttempts={3} // Optional
/>

Props

| Prop | Type | Required | Description | | ------------------------ | -------------- | -------- | -------------------------------------------- | | selectedFlowEndpointId | number | Yes | ID of the selected flow endpoint | | flowEnabled | boolean | Yes | Whether the flow is enabled | | getUploadInterceptor | () => Function | Yes | Function to get the upload interceptor | | autoUpload | boolean | Yes | Whether to start upload automatically | | assumeFirstServerPath | boolean | Yes | Whether to assume the first server path | | retryDelayMs | number | No | Delay between retry attempts in milliseconds | | retryAttempts | number | No | Maximum number of retry attempts |

Implementation Guide

Basic HTML Implementation

  1. Add the required scripts and styles to your HTML page:
<script type="module" src="https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.css" />
  1. Add the web component to your HTML:
<thru-upload
  api-key="your-api-key"
  flow-endpoint-id="123"
  api-url="https://your-api-url.com/api"
></thru-upload>
  1. Optionally, add event listeners for upload events:
document.addEventListener("DOMContentLoaded", () => {
  window.addEventListener("thru-upload-completed", (e) => {
    console.log("Upload completed:", e.detail)
  })
})

Advanced Usage

Triggering Uploads Manually

If you set auto-upload="false", you'll need to trigger uploads manually:

// Get the upload component
const uploadComponent = document.querySelector("thru-upload")

// Trigger uploads when a button is clicked
document.querySelector("#upload-button").addEventListener("click", async () => {
  const results = await uploadComponent.triggerUploads()
  console.log("Upload results:", results)
})

Custom Upload Interception

Implement an upload interceptor to modify upload context:

const uploadComponent = document.querySelector("thru-upload")

uploadComponent.uploadInterceptor = async (context) => {
  // Add metadata or modify paths
  context.filePath = `user_${userId}/${context.filePath}`
  
  // You can make API calls here if needed
  const additionalData = await fetchUserUploadPreferences()
  
  // Return the modified context
  return {
    ...context,
    ...additionalData
  }
}

React/Next.js Integration

When using with React or Next.js:

import { useEffect, useRef } from "react"

// Load the web component scripts
useEffect(() => {
  const script = document.createElement("script")
  script.src = "https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.js"
  script.type = "module"
  document.head.appendChild(script)
  
  const link = document.createElement("link")
  link.rel = "stylesheet"
  link.href = "https://cdn.jsdelivr.net/npm/thru-mft-webcomponents/dist/assets/main.css"
  document.head.appendChild(link)
  
  return () => {
    document.head.removeChild(script)
    document.head.removeChild(link)
  }
}, [])

// Component that uses the web component
const FileUploader = ({ apiKey, flowEndpointId, apiUrl }) => {
  const uploadRef = useRef(null)
  
  useEffect(() => {
    if (uploadRef.current) {
      // Set up interceptor
      uploadRef.current.uploadInterceptor = (context) => {
        // Modify context
        return context
      }
      
      // Listen for completion events
      const handleUploadComplete = (e) => {
        console.log("Upload completed:", e.detail)
      }
      
      window.addEventListener("thru-upload-completed", handleUploadComplete)
      
      return () => {
        window.removeEventListener("thru-upload-completed", handleUploadComplete)
      }
    }
  }, [uploadRef.current])
  
  return (
    <div>
      <thru-upload
        ref={uploadRef}
        api-key={apiKey}
        flow-endpoint-id={flowEndpointId}
        api-url={apiUrl}
        auto-upload="true"
      ></thru-upload>
      
      <button onClick={() => uploadRef.current?.triggerUploads()}>
        Upload Files
      </button>
    </div>
  )
}

Technical Details

ResumableUploadContext

The upload context contains all the information needed for the upload:

type ResumableUploadContext = {
  flowCode: string
  endpointCode: string
  flowEndpointId: number
  serverPath: string
  fileName: string
  filePath: string
  fileSize: number
  lastUploadedChunkIndex?: number
  sessionUID?: string
  reportId?: string
  chunkSize?: number
  outcome?: {
    success: boolean
    error?: any
  }
}

Chunked Upload Process

Files are uploaded in chunks of 100MB by default:

const CHUNK_SIZE = 100 * 1024 * 1024 // 100MB

The upload process:

  1. Create an upload session
  2. Upload chunks sequentially
  3. Track upload progress
  4. Commit the session when all chunks are uploaded
  5. Handle errors and allow retries

CSS Customization

The component uses CSS variables for styling that can be overridden:

:root {
  --primary-color: #4051a5;
  --primary-color-bg: rgba(64, 81, 165, 0.1);
  --primary-color-dark: #062491;
  --off-theme-color: #415362;
  --off-theme-color-accent: #5f778a;
  --error-color: #d93025;
  --theme-delete-color: #d93025;
  --loader-color-bg: #e6e6e6;
}