@pushduck/cli
Version:
Official CLI for pushduck - Add S3 upload functionality to your Next.js project
351 lines (261 loc) ⢠9.44 kB
Markdown
# Pushduck CLI
[](https://www.npmjs.com/package/@pushduck/cli)
[](https://www.npmjs.com/package/@pushduck/cli)
[](https://www.typescriptlang.org/)
[](https://opensource.org/licenses/MIT)
[](https://discord.gg/pushduck)
[](https://twitter.com/intent/tweet?text=Just%20discovered%20%40pushduck%20-%20the%20fastest%20way%20to%20add%20file%20uploads%20to%20any%20web%20app!%20š¦%20https%3A//github.com/abhay-ramesh/pushduck)
Zero-configuration setup for Next.js file uploads. Get production-ready S3 uploads working in under 2 minutes.
## Quick Start
```bash
npx /cli init
```
That's it! The CLI will guide you through setting up:
- ā
Provider configuration (AWS S3, Cloudflare R2, etc.)
- ā
API route generation with TypeScript
- ā
Example upload components
- ā
Environment variable setup
- ā
Bucket creation (optional)
## Commands
### `init` - Initialize Your Project
```bash
npx /cli init [options]
```
**Options:**
- `--provider <type>` - Skip provider selection (aws|cloudflare-r2|digitalocean|minio|gcs)
- `--skip-examples` - Don't generate example components
- `--skip-bucket` - Don't create S3 bucket automatically
- `--api-path <path>` - Custom API route path (default: `/api/upload`)
- `--dry-run` - Show what would be created without creating
- `--verbose` - Show detailed output
**Examples:**
```bash
# Interactive setup with all prompts
npx /cli init
# Use AWS S3 directly, skip examples
npx /cli init --provider aws --skip-examples
# Custom API path
npx /cli@latest init --api-path /api/files
# Preview without creating files
npx /cli init --dry-run
```
### `add` - Add Upload Routes
```bash
npx /cli add
```
Add new upload routes to your existing configuration. Interactive route builder helps you:
- Define file types and validation
- Set up middleware and authentication
- Configure upload destinations
- Generate TypeScript types
### `test` - Validate Setup
```bash
npx /cli test [--verbose]
```
Validates your current configuration:
- ā
Environment variables
- ā
S3 bucket connectivity
- ā
CORS configuration
- ā
API route functionality
- ā
TypeScript compilation
## What Gets Created
The CLI generates a complete, production-ready setup:
```
your-project/
āāā app/api/upload/route.ts # Type-safe upload API
āāā app/upload/page.tsx # Demo upload page
āāā components/ui/
ā āāā upload-button.tsx # Simple upload button
ā āāā upload-dropzone.tsx # Drag & drop component
ā āāā file-preview.tsx # File preview component
āāā lib/upload-client.ts # Type-safe upload client
āāā .env.local # Environment variables
āāā .env.example # Environment template
```
### Generated API Route
```typescript
// app/api/upload/route.ts
import { createUploadRouter, uploadSchema } from 'pushduck/server'
export const router = createUploadRouter({
imageUpload: uploadSchema({
image: {
maxSize: "5MB",
maxCount: 1,
formats: ["jpeg", "png", "webp"]
}
}).middleware(async ({ req }) => {
// Add your authentication logic
const userId = await getUserId(req)
return { userId, folder: `uploads/${userId}` }
}),
documentUpload: uploadSchema({
file: {
maxSize: "10MB",
maxCount: 5,
allowedTypes: ["application/pdf", "text/plain"]
}
}).middleware(async ({ req }) => {
const userId = await getUserId(req)
return { userId, folder: `documents/${userId}` }
})
})
export type AppRouter = typeof router
export const { GET, POST } = router
```
### Generated Upload Client
```typescript
// lib/upload-client.ts
import { createUploadClient } from 'pushduck/client'
import type { AppRouter } from '@/app/api/upload/route'
export const upload = createUploadClient<AppRouter>({
endpoint: '/api/upload'
})
// Property-based access with full type safety
export const { imageUpload, documentUpload } = upload
```
### Generated Components
```typescript
// components/ui/upload-button.tsx
'use client'
import { upload } from '@/lib/upload-client'
export function UploadButton() {
const { uploadFiles, uploadedFiles, isUploading, progress } = upload.imageUpload()
return (
<div>
<input
type="file"
onChange={(e) => uploadFiles(e.target.files)}
disabled={isUploading}
/>
{isUploading && <div>Progress: {progress}%</div>}
{uploadedFiles.map(file => (
<img key={file.key} src={file.url} alt="Uploaded" />
))}
</div>
)
}
```
## Provider Support
The CLI supports all major S3-compatible providers:
- **AWS S3** - The original and most feature-complete
- **Cloudflare R2** - Global edge network, S3-compatible
- **DigitalOcean Spaces** - Simple and affordable
- **Google Cloud Storage** - Enterprise-grade with global reach
- **MinIO** - Self-hosted, open source S3 alternative
### Provider-Specific Setup
Each provider has tailored setup:
```bash
# AWS S3 with automatic IAM policy creation
npx /cli init --provider aws
# Cloudflare R2 with edge optimization
npx /cli init --provider cloudflare-r2
# DigitalOcean Spaces with CDN setup
npx /cli init --provider digitalocean
# MinIO for local development
npx /cli init --provider minio
```
## Interactive Setup Flow
The CLI provides a guided setup experience:
```
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā
ā š Welcome to Pushduck ā
ā ā
ā Let's get your file uploads working in 2 minutes! ā
ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
š Detecting your project...
ā Next.js App Router detected
ā TypeScript configuration found
ā No existing upload configuration
? Which cloud storage provider would you like to use?
⯠AWS S3 (recommended)
Cloudflare R2 (S3-compatible, global edge)
DigitalOcean Spaces (simple, affordable)
š§ Setting up AWS S3...
š Checking for existing credentials...
ā Found AWS_ACCESS_KEY_ID
ā Found AWS_SECRET_ACCESS_KEY
ā Found AWS_REGION
? Enter your S3 bucket name: my-app-uploads
? Create bucket automatically? Yes
š ļø Generating files...
⨠Created files:
āāā app/api/upload/route.ts
āāā app/upload/page.tsx
āāā components/ui/upload-button.tsx
āāā lib/upload-client.ts
āāā .env.example
š¦ Installing dependencies...
ā pushduck
ā react-dropzone
š Setup complete! Your uploads are ready.
```
## Troubleshooting
### CLI Not Found
```bash
# If you get "command not found"
npm install -g pushduck
# Or use npx for one-time usage
npx /cli init
```
### Permission Errors
```bash
# If you get permission errors during setup
sudo npx /cli init
# Or fix npm permissions
npm config set prefix ~/.npm-global
export PATH=~/.npm-global/bin:$PATH
```
### Bucket Creation Failed
```bash
# Test your credentials first
npx /cli test
# Skip automatic bucket creation
npx /cli init --skip-bucket
# Create bucket manually, then run:
npx /cli test
```
## Advanced Usage
### Non-Interactive Mode
```bash
# For CI/CD environments
npx /cli init \
--provider aws \
--skip-examples \
--api-path /api/upload \
--no-interactive
```
### Custom Templates
```bash
# Use enterprise template with security features
npx /cli init --template enterprise
# Use minimal template for existing projects
npx /cli init --template minimal
```
### Monorepo Support
```bash
# For monorepos, specify the Next.js app directory
cd apps/web
npx /cli init
# Or use the --cwd flag
npx /cli@latest init --cwd apps/web
```
## Contributing
The CLI is part of the [pushduck monorepo](https://github.com/your-org/pushduck).
```bash
# Clone the repository
git clone https://github.com/your-org/pushduck.git
# Install dependencies
pnpm install
# Development
cd packages/cli
pnpm dev
# Build
pnpm build
# Test locally
npm link
pushduck init
```
## License
MIT Ā© [Abhay Ramesh](https://github.com/abhayramesh)