Middleware
Transform streams and hook into upload lifecycle
Middleware lets you intercept and transform file uploads before they reach the driver, and trigger actions after uploads complete.
Interface
interface MiddlewareHook {
beforeUpload?: (
stream: ReadableStream<Uint8Array>,
options: UploadOptions,
) => Promise<
| { stream?: ReadableStream<Uint8Array>; options?: UploadOptions }
| void
>;
afterUpload?: (
result: UploadResult<Record<string, unknown>>,
) => Promise<void>;
}beforeUpload
Runs before the driver receives the stream. You can replace the stream (e.g. compress, encrypt, validate) or modify upload options (e.g. inject metadata, rewrite filenames).
Return { stream }, { options }, both, or undefined to pass through unchanged.
import { FilewayClient, MiddlewareHook } from "@fileway/core";
const sizeLimit: MiddlewareHook = {
async beforeUpload(stream, options) {
const reader = stream.getReader();
const chunks: Uint8Array[] = [];
let total = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
total += value.length;
}
if (total > 10 * 1024 * 1024) {
throw new Error("File exceeds 10MB limit");
}
return {
stream: new ReadableStream({
start(controller) {
for (const chunk of chunks) controller.enqueue(chunk);
controller.close();
},
}),
};
},
};afterUpload
Runs after the driver returns a successful upload result. Useful for logging, webhook calls, database indexing, or cache invalidation.
const logger: MiddlewareHook = {
async afterUpload(result) {
console.log(`Uploaded ${result.path} (${result.size} bytes)`);
},
};Usage
Pass middleware via the middlewares array in the client config:
const client = new FilewayClient({
driver: new LocalDriver({ directory: "./uploads" }),
middlewares: [sizeLimit, logger],
});
await client.upload(stream, { filename: "report.pdf" });
// → beforeUpload runs first (size check)
// → driver uploads
// → afterUpload runs (log)Middleware runs in the order they are defined. All beforeUpload hooks execute first (in order), then the driver upload, then all afterUpload hooks (in order).
Example: Metadata Injection
const injectMeta: MiddlewareHook = {
beforeUpload(_stream, options) {
const timestamp = Date.now().toString();
return {
options: {
...options,
metadata: {
...options.metadata,
uploadedAt: timestamp,
},
},
};
},
};Example: Stream Compression
import { FilewayClient, MiddlewareHook } from "@fileway/core";
const compressor: MiddlewareHook = {
async beforeUpload(stream) {
const compressed = stream.pipeThrough(new CompressionStream("gzip"));
return { stream: compressed };
},
};