mirror of
https://github.com/skills-shell/superpowers.git
synced 2026-09-18 09:07:07 +08:00
d91c4376f2
Restructure the repository for better organization: - tools/ - App & model running skills - image/ (ai-image-generation, flux-image, nano-banana, qwen-image-2, etc.) - video/ (ai-video-generation, google-veo, ai-avatar-video, etc.) - audio/ (text-to-speech, speech-to-text, ai-music-generation, etc.) - llm/ (llm-models, web-search, ai-rag-pipeline) - social/ (twitter-automation) - utilities/ (agentic-browser, python-executor, related-skill) - agent-tools/ - sdk/ - SDK documentation - javascript-sdk/ - python-sdk/ - ui/ - UI components - agent-ui, chat-ui, tools-ui, widgets-ui - guides/ - How-to guides & workflows - content/, design/, photo/, product/ - prompting/, social/, video/, writing/ Update README to reflect new structure.
8.4 KiB
8.4 KiB
Server Proxy Setup
Secure API key handling for frontend applications.
Why Use a Proxy?
Never expose API keys in browser code. Use a server proxy to:
- Keep API keys secure on the server
- Add authentication/authorization
- Rate limit requests
- Log usage and analytics
Browser (SDK) → Your Backend (Proxy) → api.inference.sh
(no key) (injects API key) (authenticated)
Client Configuration
import { inference } from '@inferencesh/sdk';
// Frontend code - no API key!
const client = inference({
proxyUrl: '/api/inference/proxy'
});
// Use normally
const result = await client.run({
app: 'infsh/flux-schnell',
input: { prompt: 'A sunset' }
});
Next.js (App Router)
// app/api/inference/proxy/route.ts
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
const route = createRouteHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
export const POST = route.POST;
With Custom Authentication
// app/api/inference/proxy/route.ts
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
import { getServerSession } from 'next-auth';
const route = createRouteHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
export async function POST(req: Request) {
// Check auth first
const session = await getServerSession();
if (!session) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// Check rate limits, log usage, etc.
return route.POST(req);
}
Next.js (Pages Router)
// pages/api/inference/proxy.ts
import { createApiHandler } from '@inferencesh/sdk/proxy/nextjs-pages';
export default createApiHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
Express
import express from 'express';
import { createProxyMiddleware } from '@inferencesh/sdk/proxy/express';
const app = express();
// Basic setup
app.use('/api/inference/proxy', createProxyMiddleware({
apiKey: process.env.INFERENCE_API_KEY!
}));
// With auth middleware
app.use('/api/inference/proxy',
requireAuth,
createProxyMiddleware({
apiKey: process.env.INFERENCE_API_KEY!
})
);
app.listen(3000);
Hono
import { Hono } from 'hono';
import { createMiddleware } from '@inferencesh/sdk/proxy/hono';
const app = new Hono();
app.post('/api/inference/proxy', createMiddleware({
apiKey: process.env.INFERENCE_API_KEY!
}));
export default app;
Cloudflare Workers
import { Hono } from 'hono';
import { createMiddleware } from '@inferencesh/sdk/proxy/hono';
type Bindings = {
INFERENCE_API_KEY: string;
};
const app = new Hono<{ Bindings: Bindings }>();
app.post('/api/inference/proxy', (c) => {
const middleware = createMiddleware({
apiKey: c.env.INFERENCE_API_KEY
});
return middleware(c);
});
export default app;
Remix
// app/routes/api.inference.proxy.tsx
import type { ActionFunctionArgs } from '@remix-run/node';
import { createActionHandler } from '@inferencesh/sdk/proxy/remix';
const handler = createActionHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
export const action = async ({ request }: ActionFunctionArgs) => {
return handler(request);
};
SvelteKit
// src/routes/api/inference/proxy/+server.ts
import { createRequestHandler } from '@inferencesh/sdk/proxy/sveltekit';
import { INFERENCE_API_KEY } from '$env/static/private';
const handler = createRequestHandler({
apiKey: INFERENCE_API_KEY
});
export const POST = handler;
Dynamic API Key Resolution
Load API keys from secrets managers:
// Next.js example
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
import { getSecret } from './vault';
const route = createRouteHandler({
resolveApiKey: async () => {
return await getSecret('INFERENCE_API_KEY');
}
});
export const POST = route.POST;
Per-User API Keys
Use different keys per user/organization:
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
import { getServerSession } from 'next-auth';
import { db } from './db';
const route = createRouteHandler({
resolveApiKey: async (req) => {
const session = await getServerSession();
if (!session?.user) {
throw new Error('Unauthorized');
}
// Get user's API key from database
const user = await db.user.findUnique({
where: { id: session.user.id },
select: { inferenceApiKey: true }
});
return user?.inferenceApiKey || process.env.DEFAULT_INFERENCE_API_KEY!;
}
});
export const POST = route.POST;
Rate Limiting
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '1 m'), // 10 requests per minute
});
const route = createRouteHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
export async function POST(req: Request) {
// Get user identifier
const ip = req.headers.get('x-forwarded-for') || 'anonymous';
// Check rate limit
const { success, limit, reset, remaining } = await ratelimit.limit(ip);
if (!success) {
return Response.json(
{ error: 'Rate limit exceeded' },
{
status: 429,
headers: {
'X-RateLimit-Limit': limit.toString(),
'X-RateLimit-Remaining': remaining.toString(),
'X-RateLimit-Reset': reset.toString()
}
}
);
}
return route.POST(req);
}
Usage Logging
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
import { getServerSession } from 'next-auth';
const route = createRouteHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
export async function POST(req: Request) {
const session = await getServerSession();
const body = await req.clone().json();
// Log before
console.log({
type: 'inference_request',
userId: session?.user?.id,
app: body.app,
timestamp: new Date().toISOString()
});
const response = await route.POST(req);
// Log after
console.log({
type: 'inference_response',
userId: session?.user?.id,
status: response.status,
timestamp: new Date().toISOString()
});
return response;
}
Error Handling
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
const route = createRouteHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
export async function POST(req: Request) {
try {
return await route.POST(req);
} catch (error) {
console.error('Proxy error:', error);
// Don't expose internal errors to client
return Response.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
Vercel Deployment
// vercel.json
{
"functions": {
"app/api/inference/proxy/route.ts": {
"maxDuration": 60
}
}
}
// app/api/inference/proxy/route.ts
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
const route = createRouteHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
export const POST = route.POST;
// Enable streaming for long-running requests
export const runtime = 'edge';
CORS Configuration
If your frontend and backend are on different domains:
import { createRouteHandler } from '@inferencesh/sdk/proxy/nextjs';
const route = createRouteHandler({
apiKey: process.env.INFERENCE_API_KEY!
});
export async function POST(req: Request) {
const response = await route.POST(req);
// Add CORS headers
const headers = new Headers(response.headers);
headers.set('Access-Control-Allow-Origin', 'https://your-frontend.com');
headers.set('Access-Control-Allow-Methods', 'POST');
headers.set('Access-Control-Allow-Headers', 'Content-Type');
return new Response(response.body, {
status: response.status,
headers
});
}
export async function OPTIONS() {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': 'https://your-frontend.com',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
}
});
}
Testing Locally
// Use environment variable for flexibility
const client = inference({
// Use proxy in production, direct API in development
...(process.env.NODE_ENV === 'production'
? { proxyUrl: '/api/inference/proxy' }
: { apiKey: process.env.NEXT_PUBLIC_INFERENCE_API_KEY })
});