Framework Integrations

Elysia

TypeScript-first framework with Bun - Web Standards native, no adapter needed!

Elysia

Elysia is a TypeScript-first web framework designed for Bun. Since Elysia uses Web Standard Request objects natively, pushduck handlers work directly without any adapters!

Web Standards Native: Elysia exposes context.request as a Web Standard Request object, making pushduck integration seamless with zero overhead.

Quick Setup

Install dependencies

bun add pushduck
npm install pushduck
yarn add pushduck
pnpm add pushduck

Configure upload router

lib/upload.ts
import { createUploadConfig } from 'pushduck/server';

const { s3, createS3Router } = createUploadConfig()
  .provider("cloudflareR2",{
    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
    region: 'auto',
    endpoint: process.env.AWS_ENDPOINT_URL!,
    bucket: process.env.S3_BUCKET_NAME!,
    accountId: process.env.R2_ACCOUNT_ID!,
  })
  .build();

export const uploadRouter = createS3Router({
  imageUpload: s3.image().max("5MB"),
  documentUpload: s3.file().max("10MB")
});

export type AppUploadRouter = typeof uploadRouter;

Create Elysia app with upload routes

server.ts
import { Elysia } from 'elysia';
import { uploadRouter } from './lib/upload';

const app = new Elysia();

// Direct usage - no adapter needed!
app.all('/api/upload/*', (context) => {
  return uploadRouter.handlers(context.request);
});

app.listen(3000);

Basic Integration

Simple Upload Route

server.ts
import { Elysia } from 'elysia';
import { uploadRouter } from './lib/upload';

const app = new Elysia();

// Method 1: Combined handler (recommended)
app.all('/api/upload/*', (context) => {
  return uploadRouter.handlers(context.request);
});

// Method 2: Separate handlers (if you need method-specific logic)
app.get('/api/upload/*', (context) => uploadRouter.handlers.GET(context.request));
app.post('/api/upload/*', (context) => uploadRouter.handlers.POST(context.request));

app.listen(3000);

With Middleware and CORS

server.ts
import { Elysia } from 'elysia';
import { cors } from '@elysiajs/cors';
import { uploadRouter } from './lib/upload';

const app = new Elysia()
  .use(cors({
    origin: ['http://localhost:3000', 'https://your-domain.com'],
    allowedHeaders: ['Content-Type', 'Authorization'],
    methods: ['GET', 'POST']
  }))
  
  // Upload routes
  .all('/api/upload/*', (context) => uploadRouter.handlers(context.request))
  
  // Health check
  .get('/health', () => ({ status: 'ok' }))
  
  .listen(3000);

console.log(`🦊 Elysia is running at http://localhost:3000`);

Advanced Configuration

Authentication with JWT

lib/upload.ts
import { createUploadConfig } from 'pushduck/server';
import jwt from '@elysiajs/jwt';

const { s3, createS3Router } = createUploadConfig()
  .provider("cloudflareR2",{
    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
    region: 'auto',
    endpoint: process.env.AWS_ENDPOINT_URL!,
    bucket: process.env.S3_BUCKET_NAME!,
    accountId: process.env.R2_ACCOUNT_ID!,
  })
  .paths({
    prefix: 'uploads',
    generateKey: (file, metadata) => {
      return `${metadata.userId}/${Date.now()}/${file.name}`;
    }
  })
  .build();

export const uploadRouter = createS3Router({
  // Private uploads with JWT authentication
  privateUpload: s3
    .image()
    .max("5MB")
    .middleware(async ({ req }) => {
      const authHeader = req.headers.get('authorization');
      if (!authHeader?.startsWith('Bearer ')) {
        throw new Error('Authorization required');
      }

      const token = authHeader.substring(7);
      
      try {
        // Use your JWT verification logic here
        const payload = jwt.verify(token, process.env.JWT_SECRET!);
        return {
          userId: payload.sub as string,
          userRole: payload.role as string
        };
      } catch (error) {
        throw new Error('Invalid token');
      }
    }),

  // Public uploads (no auth)
  publicUpload: s3
    .image()
    .max("2MB")
    // No middleware = public access
});

export type AppUploadRouter = typeof uploadRouter;

Full Production Setup

server.ts
import { Elysia } from 'elysia';
import { cors } from '@elysiajs/cors';
import { rateLimit } from '@elysiajs/rate-limit';
import { swagger } from '@elysiajs/swagger';
import { uploadRouter } from './lib/upload';

const app = new Elysia()
  // Swagger documentation
  .use(swagger({
    documentation: {
      info: {
        title: 'Upload API',
        version: '1.0.0'
      }
    }
  }))
  
  // CORS
  .use(cors({
    origin: process.env.NODE_ENV === 'production' 
      ? ['https://your-domain.com'] 
      : true,
    allowedHeaders: ['Content-Type', 'Authorization'],
    methods: ['GET', 'POST']
  }))
  
  // Rate limiting
  .use(rateLimit({
    max: 100,
    windowMs: 15 * 60 * 1000, // 15 minutes
  }))
  
  // Upload routes
  .all('/api/upload/*', (context) => uploadRouter.handlers(context.request))
  
  // Health check
  .get('/health', () => ({ 
    status: 'ok', 
    timestamp: new Date().toISOString() 
  }))
  
  .listen(process.env.PORT || 3000);

console.log(`🦊 Elysia is running at http://localhost:${process.env.PORT || 3000}`);

TypeScript Integration

Type-Safe Client

lib/upload-client.ts
import { createUploadClient } from 'pushduck/client';
import type { AppUploadRouter } from './upload';

export const uploadClient = createUploadClient<AppUploadRouter>({
  baseUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'
});

Client Usage

components/upload.tsx
import { uploadClient } from '../lib/upload-client';

export function UploadComponent() {
  const handleUpload = async (files: File[]) => {
    try {
      const results = await uploadClient.upload('imageUpload', {
        files,
        // Type-safe metadata based on your router configuration
        metadata: { userId: 'user-123' }
      });
      
      console.log('Upload successful:', results);
    } catch (error) {
      console.error('Upload failed:', error);
    }
  };

  return (
    <input 
      type="file" 
      multiple 
      onChange={(e) => {
        if (e.target.files) {
          handleUpload(Array.from(e.target.files));
        }
      }}
    />
  );
}

Performance Benefits

🚀 Zero Overhead

Direct Web Standards integration

No adapter layer means zero performance overhead - pushduck handlers run directly in Elysia.

⚡ Bun Performance

Ultra-fast JavaScript runtime

Built for Bun's exceptional performance, perfect for high-throughput upload APIs.

📝 TypeScript First

End-to-end type safety

Full TypeScript support from server to client with compile-time safety.

🔧 Plugin Ecosystem

Rich middleware support

Extensive plugin ecosystem for authentication, validation, rate limiting, and more.

Deployment

Production Deployment

Dockerfile
FROM oven/bun:1 as base
WORKDIR /usr/src/app

# Install dependencies
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile

# Copy source code
COPY . .

# Expose port
EXPOSE 3000

# Run the app
CMD ["bun", "run", "server.ts"]
# Build and run
docker build -t my-upload-api .
docker run -p 3000:3000 my-upload-api

Perfect TypeScript Integration: Elysia's TypeScript-first approach combined with pushduck's type-safe design creates an exceptional developer experience with full end-to-end type safety.