Files
okaris d91c4376f2 refactor: reorganize skills into tools, guides, sdk, and ui
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.
2026-03-03 21:46:56 +01:00

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 })
});