@howells/stow-next
Next.js integration for Stow file storage. Includes route handler helpers and an image loader for next/image.
Installation
npm install @howells/stow-next @howells/stow-server
pnpm add @howells/stow-next @howells/stow-server
yarn add @howells/stow-next @howells/stow-server
Quick Start
1. Create an upload route
import { createUploadHandler } from "@howells/stow-next";
import { StowServer } from "@howells/stow-server";
const stow = new StowServer(process.env.STOW_API_KEY!);
export const POST = createUploadHandler({
stow,
maxSize: 10 * 1024 * 1024,
allowedTypes: ["image/*", "application/pdf"],
});
2. Use with @howells/stow-react
import { UploadDropzone } from "@howells/stow-react";
export default function Page() {
return <UploadDropzone endpoint="/api/upload" onUploadComplete={(files) => console.log(files)} />;
}
Route Handler
createUploadHandler(config)
Creates a Next.js route handler for file uploads.
import { createUploadHandler } from "@howells/stow-next";
export const POST = createUploadHandler({
stow: new StowServer(process.env.STOW_API_KEY!),
maxSize: 10 * 1024 * 1024,
allowedTypes: ["image/*", ".pdf"],
route: "uploads",
validate: async (file) => {
if (file.name.includes("secret")) {
return "Filename not allowed";
}
return true;
},
onUploadBegin: async (file) => {
console.log(`Starting upload: ${file.name}`);
},
onUploadComplete: async (result) => {
console.log(`Uploaded: ${result.url}`);
},
});
Image Loader
Use Stow's image transformation with Next.js Image component.
Setup
module.exports = {
images: {
loader: "custom",
loaderFile: "./lib/stow-loader.ts",
},
};
import { stowLoader } from "@howells/stow-next/image-loader";
export default stowLoader;
Usage
import Image from "next/image";
function MyComponent() {
return (
<Image
src="https://stow.sh/files/bucket-id/image.jpg"
alt="My image"
width={800}
height={600}
quality={80}
/>
);
}
Custom Loader Config
import { createStowLoader } from "@howells/stow-next/image-loader";
export default createStowLoader({
baseUrl: "https://stow.sh",
defaultQuality: 80,
defaultFormat: "webp",
});
TypeScript
import type { UploadHandlerConfig, StowLoaderConfig } from "@howells/stow-next";
Complete Example
import { createUploadHandler } from "@howells/stow-next";
import { StowServer } from "@howells/stow-server";
import { db } from "@/lib/db";
import { auth } from "@/lib/auth";
const stow = new StowServer(process.env.STOW_API_KEY!);
export const POST = createUploadHandler({
stow,
maxSize: 5 * 1024 * 1024,
allowedTypes: ["image/jpeg", "image/png", "image/webp"],
validate: async (file) => {
const session = await auth();
if (!session) return "Unauthorized";
return true;
},
onUploadComplete: async (result) => {
const session = await auth();
await db.insert(files).values({
key: result.key,
url: result.url,
userId: session!.user.id,
});
},
});
License
MIT