
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
@rodgerai/nextjs
Advanced tools
Next.js integration for Rodger.ai - Production-ready AI agents with auth, storage, and tool approval
Production-ready AI chat handlers for Next.js with authentication, storage, and tool approval.
The perfect companion to Vercel AI SDK - adds production features without hiding the AI SDK.
npm install @rodger/nextjs ai
# Choose your AI provider
npm install @ai-sdk/openai
# or
npm install @ai-sdk/anthropic
// app/api/chat/route.ts
import { createChatHandler } from '@rodger/nextjs';
import { openai } from '@ai-sdk/openai';
export const POST = createChatHandler({
model: openai('gpt-4o'),
systemPrompt: 'You are a helpful assistant.'
});
That's it! You now have a production-ready chat endpoint at /api/chat.
// app/api/chat/route.ts
import { createChatHandler } from '@rodger/nextjs';
import { openai } from '@ai-sdk/openai';
export const POST = createChatHandler({
model: openai('gpt-4o'),
systemPrompt: 'You are a helpful assistant.',
auth: true // Auto-detects Clerk, Supabase, NextAuth, Auth0
});
// app/api/chat/route.ts
import { createChatHandler, createSupabaseStorage } from '@rodger/nextjs';
import { openai } from '@ai-sdk/openai';
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
const storage = createSupabaseStorage({
connection: supabase,
tables: {
messages: 'chat_messages',
sessions: 'chat_sessions'
}
});
export const POST = createChatHandler({
model: openai('gpt-4o'),
systemPrompt: 'You are a helpful assistant.',
auth: true,
storage
});
// app/api/chat/route.ts
import { createChatHandler } from '@rodger/nextjs';
import { openai } from '@ai-sdk/openai';
import { tool } from 'ai';
import { z } from 'zod';
const weatherTool = tool({
description: 'Get current weather',
parameters: z.object({
location: z.string()
}),
execute: async ({ location }) => {
// Your weather API call
return { temperature: 72, conditions: 'Sunny' };
}
});
export const POST = createChatHandler({
model: openai('gpt-4o'),
systemPrompt: 'You are a helpful assistant with access to weather data.',
tools: {
getCurrentWeather: weatherTool
}
});
Require user confirmation before executing sensitive tools:
import { createChatHandler, withApproval } from '@rodger/nextjs';
import { openai } from '@ai-sdk/openai';
import { tool } from 'ai';
import { z } from 'zod';
const deleteUserTool = withApproval(
tool({
description: 'Delete a user account',
parameters: z.object({
userId: z.string()
}),
execute: async ({ userId }) => {
// Delete user logic
return { success: true };
}
}),
{
message: (args) => `Are you sure you want to delete user ${args.userId}?`,
timeout: 30000 // 30 seconds
}
);
export const POST = createChatHandler({
model: openai('gpt-4o'),
tools: {
deleteUser: deleteUserTool
}
});
createChatHandler(config, options?)Create a Next.js route handler for AI chat.
| Property | Type | Description |
|---|---|---|
model | any | Required. AI SDK model instance (e.g., openai('gpt-4o')) |
systemPrompt | string | (ctx) => string | System prompt for the agent |
tools | Record<string, CoreTool> | Tools available to the agent |
storage | StorageAdapter | Storage adapter for message persistence |
auth | boolean | AuthContext | Enable authentication (auto-detects provider) |
temperature | number | Temperature for model (0-2) |
maxTokens | number | Maximum tokens to generate |
maxSteps | number | Maximum number of tool call steps |
onStart | (ctx) => void | Callback before streaming starts |
onComplete | (ctx, result) => void | Callback when streaming completes |
onError | (ctx, error) => void | Callback on error |
createMemoryStorage()In-memory storage (for development only):
import { createMemoryStorage } from '@rodger/nextjs';
const storage = createMemoryStorage();
createSupabaseStorage(config)Supabase storage adapter:
import { createSupabaseStorage } from '@rodger/nextjs';
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
const storage = createSupabaseStorage({
connection: supabase,
tables: {
messages: 'chat_messages',
sessions: 'chat_sessions'
}
});
See Database Schema for required tables.
createPostgresStorage(config)PostgreSQL storage adapter:
import { createPostgresStorage } from '@rodger/nextjs';
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
const storage = createPostgresStorage({
connection: pool,
tables: {
messages: 'chat_messages',
sessions: 'chat_sessions'
}
});
createRedisStorage(config)Redis storage adapter:
import { createRedisStorage } from '@rodger/nextjs';
import { createClient } from 'redis';
const redis = createClient({
url: process.env.REDIS_URL
});
await redis.connect();
const storage = createRedisStorage({
connection: redis,
options: {
keyPrefix: 'chat:',
messageTTL: 86400 * 30 // 30 days
}
});
export const POST = createChatHandler({
model: openai('gpt-4o'),
auth: true // Auto-detects provider
});
Supports:
@clerk/nextjs)@supabase/ssr)next-auth)@auth0/nextjs-auth0)import { detectClerkAuth } from '@rodger/nextjs';
export const POST = createChatHandler({
model: openai('gpt-4o'),
auth: detectClerkAuth
});
withApproval(tool, config?)Wrap a tool to require user approval:
import { withApproval } from '@rodger/nextjs';
import { tool } from 'ai';
import { z } from 'zod';
const sensitiveTool = withApproval(
tool({
description: 'Perform sensitive operation',
parameters: z.object({
data: z.string()
}),
execute: async ({ data }) => {
// Sensitive operation
return { success: true };
}
}),
{
message: 'Approve this operation?',
timeout: 60000, // 1 minute
autoApproveOnTimeout: false
}
);
Config:
message: Message or function that returns messagetimeout: Timeout in milliseconds (default: 60000)autoApproveOnTimeout: Auto-approve after timeout (default: false)onApprovalRequest: Custom approval handler-- Messages table
CREATE TABLE chat_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id TEXT NOT NULL,
role TEXT NOT NULL,
content TEXT NOT NULL,
user_id TEXT,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_messages_session ON chat_messages(session_id);
CREATE INDEX idx_messages_user ON chat_messages(user_id);
-- Sessions table
CREATE TABLE chat_sessions (
id TEXT PRIMARY KEY,
user_id TEXT,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
last_message TEXT,
message_count INTEGER DEFAULT 0
);
CREATE INDEX idx_sessions_user ON chat_sessions(user_id);
See the examples directory for complete examples:
Full TypeScript support with exported types:
import type {
ChatHandlerConfig,
ChatContext,
StorageAdapter,
AuthContext,
ToolWithApproval
} from '@rodger/nextjs';
Vercel AI SDK is amazing for LLM integration, but production apps need more:
@rodger/nextjs provides these features while staying 100% transparent with AI SDK. You're still using streamText() under the hood - we just handle the production stuff.
AI SDK is a peer dependency (optional). Install the version you want:
{
"peerDependencies": {
"ai": "^5.0.0",
"@ai-sdk/openai": "^2.0.0",
"@ai-sdk/anthropic": "^2.0.0",
"next": "^14.0.0 || ^15.0.0"
}
}
This means:
MIT
See CONTRIBUTING.md
FAQs
Next.js integration for Rodger.ai - Production-ready AI agents with auth, storage, and tool approval
We found that @rodgerai/nextjs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.