@howells/stow-next
v2.4.0
Published
Next.js integration for Stow file storage
Maintainers
Readme
@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
# or
pnpm add @howells/stow-next @howells/stow-server
# or
yarn add @howells/stow-next @howells/stow-serverQuick Start
1. Create an upload route
// app/api/upload/route.ts
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, // 10MB
allowedTypes: ["image/*", "application/pdf"],
});2. Use with @howells/stow-react
// app/page.tsx
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({
// Required: Stow server instance
stow: new StowServer(process.env.STOW_API_KEY!),
// Optional: File restrictions
maxSize: 10 * 1024 * 1024, // Max file size in bytes
allowedTypes: ["image/*", ".pdf"], // Allowed MIME types or extensions
route: "uploads", // Default route/folder
// Optional: Custom validation
validate: async (file) => {
if (file.name.includes("secret")) {
return "Filename not allowed";
}
return true;
},
// Optional: Lifecycle hooks
onUploadBegin: async (file) => {
console.log(`Starting upload: ${file.name}`);
},
onUploadComplete: async (result) => {
console.log(`Uploaded: ${result.url}`);
// Save to database, etc.
},
});Image Loader
Use Stow's image transformation with Next.js Image component.
Setup
// next.config.js
module.exports = {
images: {
loader: "custom",
loaderFile: "./lib/stow-loader.ts",
},
};// 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
// lib/stow-loader.ts
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
// app/api/upload/route.ts
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
