TypeScript · MIT · zero-config

Send huge files
over any channel.

lib-filetransfer slices a file into chunks, streams them across the transport you already have — WebRTC, WebSockets, anything — and reassembles them on the other side. Retries, parallelism and range requests included. You own the wire; the library does the rest.

npm i @ludovicm67/lib-filetransfer
  • 🧩 Transport-agnostic
  • ♻️ Auto-retry
  • ⚡ Parallel
  • 🪶 ~3 dependencies

Why it exists

Everything a file transfer needs — nothing it doesn't.

The hard parts of moving large files are chunking, ordering, loss recovery and back-pressure. This library owns those, and leaves the transport entirely to you.

🔌

Transport-agnostic

The library never touches the network. Hand it any send/receive channel — a WebRTC DataChannel, a WebSocket, even a carrier pigeon — and it orchestrates the rest.

🧩

Chunked streaming

Files are split into configurable parts, so you can move gigabytes without holding the whole thing in memory at once.

♻️

Automatic retries

Lost a part? It's re-requested until it lands, with a configurable timeout and retry budget. Flaky links just work.

Parallel transfers

Fetch many parts at once behind a built-in concurrency limiter for maximum throughput without flooding the channel.

🎯

Range requests

Ask for exactly the bytes you want with offset + limit. Resume, stream, or prioritize however you like.

🛡️

Type-safe by design

Written in TypeScript with complete type definitions, so you get autocompletion and compile-time checks for free.

Live & real

See it move.

This isn't a video. Everything below runs the actual published library in your browser. Two independent pools — a sender and a receiver — talk over a simulated channel where you control the latency and packet loss. Crank the loss up and watch the retry mechanism recover every byte.

No file selected yet

Sender
Pick or generate a file to begin.
Channel
idle
Receiver
Chunks
0 / 0
Requests sent
0
Dropped
0
Retries
0
Elapsed
0 ms
Status
Ready

The mental model

Four moves, two peers.

1

Add

The sender drops a file into its pool and gets back small metadata — id, name, size, chunk count.

2

Announce

That metadata travels over your channel. The receiver stores it, now aware the file exists.

3

Request

The receiver asks for parts by offset + limit. Your callback ferries each request to the sender.

4

Reassemble

Parts stream back, get ordered and retried as needed, then become a Blob ready to open or save.

Quick start

From install to transfer in a few lines.

Both peers create a pool. The sender adds the file; the receiver stores the metadata, then triggers the download. The two snippets below are the whole contract.

sender.ts
import { TransferFilePool } from "@ludovicm67/lib-filetransfer";

const pool = new TransferFilePool({ maxBufferSize: 16_000 });

// 1. Add a File or Blob — get back metadata to announce.
const metadata = await pool.addFile(file, file.name);
sendToPeer({ type: "meta", metadata });

// 2. When the receiver asks for a part, read and reply.
onPeerMessage(({ fileId, offset, limit }) => {
  const data = pool.readFilePart(fileId, offset, limit);
  sendToPeer({ type: "part", fileId, offset, limit, data });
});
receiver.ts
import { TransferFilePool } from "@ludovicm67/lib-filetransfer";

const pool = new TransferFilePool({ maxBufferSize: 16_000 });

// 1. Store the announced metadata.
const fileId = pool.storeFileMetadata(metadata);

// 2. Feed incoming parts back into the pool.
onPeerMessage(({ fileId, offset, limit, data }) => {
  pool.receiveFilePart(fileId, offset, limit, data);
});

// 3. Trigger the download — parts are requested for you.
await pool.downloadFile(fileId, (fileId, offset, limit) => {
  sendToPeer({ type: "ask", fileId, offset, limit });
});

const { data } = pool.getFile(fileId);   // a ready-to-use Blob
window.open(URL.createObjectURL(data), "_blank");
utils.ts
// Some channels only carry strings. Convert both ways:
import {
  arrayBufferToString,
  stringToArrayBuffer,
} from "@ludovicm67/lib-filetransfer";

// ArrayBuffer -> base64 string (safe over a text WebSocket)
const wire = arrayBufferToString(data);

// string -> ArrayBuffer on the other end
const buffer = stringToArrayBuffer(wire);

Full method-by-method reference lives in the generated API documentation →

Ready to move some bytes?

Install it, wire your channel, and let the library handle the rest.

npm i @ludovicm67/lib-filetransfer