discord-file-system
A JavaScript package for uploading and downloading files to/from Discord using webhooks.
Discord File System is a utility library that allows you to upload and read large files using Discord webhooks as a storage mechanism. It leverages the Web Streams API for reading and writing data in small chunks, making it suitable for serverless or edge environments (e.g., Next.js App Directory on Vercel Edge Functions) where Node.js built-in modules are not available.
- Upload large files to Discord through chunked attachments.
- Retrieve previously uploaded files by streaming them back.
- Works seamlessly in modern JavaScript runtimes that support the Web Streams API, including:
- Browsers
- Edge runtimes (like Vercel's Edge Functions used in Next.js)
- Minimal dependencies and simple API.
bun add discord-file-system
To use Discord File System, you need at least one Discord webhook URL and a valid Discord bot token:
- Create a Discord Application & Bot if you haven't already.
- Add a Webhook to a channel in your server and copy the URL.
- Obtain a Bot Token from the Discord Developer Portal.
Important Note: Discord has changed their default file size limit from 25MB to 10MB. To upload larger files, your server needs Nitro Boosts. Different boost levels allow different file size limits - see: https://support.discord.com/hc/en-us/articles/360028038352-Server-Boosting-FAQ
import DiscordFileSystem from "discord-file-system";
const dfs = new DiscordFileSystem({
webhooks: [
"https://discord.com/api/webhooks/<YOUR_WEBHOOK_ID>/<YOUR_WEBHOOK_TOKEN>",
],
token: "<YOUR_DISCORD_BOT_TOKEN>",
debug: true, // Enable debug mode (optional)
});
Options:
-
webhooks
: An array of webhook URLs (at least one required). -
token
: Your bot token. -
maxUploadConc?
: Maximum upload concurrency (default is2
). -
chunkSize?
: Chunk size in bytes (default is9437184
= 9MB). Note that Discord's default file size limit is 10MB - larger uploads require server boost levels. -
restOpts?
: AdditionalRESTOptions
for @discordjs/rest (optional). -
debug?
: Enable debug mode (optional).
// Assume you have a Web ReadableStream<Uint8Array>
const readable = new ReadableStream<Uint8Array>({
start(controller) {
// Push some data (just an example)
controller.enqueue(new Uint8Array([72, 101, 108, 108, 111])); // "Hello"
controller.close();
},
});
const parts = await dfs.write(readable);
console.log(parts);
// parts might look like:
// [{ url: "https://cdn.discordapp.com/...file1", size: 1234 }, ...]
// Assume we have `parts` from the write example above
const writable = new WritableStream<Uint8Array>({
write(chunk) {
// handle chunk (Uint8Array)
// for instance, you can collect all chunks or process them as they come.
},
});
await dfs.read(writable, parts);
// The data is now streamed into the writable.
Important: This library does not rely on Node.js stream
APIs. If you have a Node.js Readable
or Writable
stream, convert it to a Web Stream before using write()
or read()
.
Node.js 18+ Example:
import { Readable } from "node:stream";
import DiscordFileSystem from "discord-file-system";
// Convert Node.js readable stream to a Web ReadableStream
const nodeReadable = Readable.from(Buffer.from("Hello Discord from Node!"));
const webReadable = Readable.toWeb(nodeReadable);
const dfs = new DiscordFileSystem({
webhooks: [
"https://discord.com/api/webhooks/<YOUR_WEBHOOK_ID>/<YOUR_WEBHOOK_TOKEN>",
],
token: "<YOUR_DISCORD_BOT_TOKEN>",
});
const parts = await dfs.write(webReadable);
console.log(parts);
To write data back to a Node.js Writable
stream, similarly convert it to a Web WritableStream
:
import { Writable } from "node:stream";
// Assume `nodeWritable` is a Node.js writable, e.g., fs.createWriteStream("output.bin")
const webWritable = Writable.toWeb(nodeWritable);
// Now call read() with the Web WritableStream
await dfs.read(webWritable, parts);
If your Node.js version does not support Readable.toWeb()
or Writable.toWeb()
, you can implement a small adapter or upgrade to a newer Node.js version that supports these conversions.
If Writable.toWeb() is not available, you can use an adapter like this:
Example Adapter:
import { Writable as NodeWritable } from "node:stream";
/**
* Converts a Node.js Writable (e.g., from fs.createWriteStream)
* into a Web WritableStream<Uint8Array> so it can be used with APIs
* that rely on Web Streams.
*/
function nodeWritableToWeb(writable: NodeWritable): WritableStream<Uint8Array> {
return new WritableStream<Uint8Array>({
write(chunk) {
return new Promise<void>((resolve, reject) => {
writable.write(chunk, (err?: Error | null) => {
if (err) reject(err);
else resolve();
});
});
},
close() {
return new Promise<void>((resolve, reject) => {
writable.end((err?: Error | null) => {
if (err) reject(err);
else resolve();
});
});
},
abort(reason) {
writable.destroy(reason instanceof Error ? reason : undefined);
},
});
}
Use nodeWritableToWeb(nodeWritable) to convert your Node.js writable stream into a Web WritableStream and then pass it to dfs.read() or other APIs requiring Web Streams.
Contributions, bug reports, and feature requests are welcome. Please open an issue or PR on the GitHub repository if you have suggestions or find bugs.
MIT