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.
TypeScript · MIT · zero-config
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
Why it exists
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.
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.
Files are split into configurable parts, so you can move gigabytes without holding the whole thing in memory at once.
Lost a part? It's re-requested until it lands, with a configurable timeout and retry budget. Flaky links just work.
Fetch many parts at once behind a built-in concurrency limiter for maximum throughput without flooding the channel.
Ask for exactly the bytes you want with offset + limit. Resume, stream, or prioritize however you like.
Written in TypeScript with complete type definitions, so you get autocompletion and compile-time checks for free.
Live & real
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
The mental model
The sender drops a file into its pool and gets back small metadata — id, name, size, chunk count.
That metadata travels over your channel. The receiver stores it, now aware the file exists.
The receiver asks for parts by offset + limit. Your callback ferries each request to the sender.
Parts stream back, get ordered and retried as needed, then become a Blob ready to open or save.
Quick start
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.
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 });
});
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");
// 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 →
Install it, wire your channel, and let the library handle the rest.
npm i @ludovicm67/lib-filetransfer