Next.js App Router handlers for Neuroline pipeline APIs.
neuroline-nextjs
Next.js App Router integration for Neuroline - provides route handlers for API routes.
Installation
yarn add neuroline neuroline-nextjs
Features
- App Router Support - native Next.js 14+ App Router integration
- Type-Safe Handlers - full TypeScript support with NextRequest/Response
- One Route = One Pipeline - each route handles exactly one pipeline type
- Job Details API - get input, options, and artifacts for individual jobs
- Stateless Design - works with serverless deployments
Quick Start
1. Create Pipeline Manager
// lib/neuroline.ts
import { PipelineManager, InMemoryPipelineStorage } from 'neuroline';
const storage = new InMemoryPipelineStorage();
export const manager = new PipelineManager({ storage });
export { storage };
2. Create API Route Handler
Create a separate route for each pipeline. For example app/api/pipeline/my-pipeline/route.ts:
import { createPipelineRouteHandler } from 'neuroline-nextjs';
import { manager, storage } from '@/lib/neuroline';
import { myPipelineConfig } from '@/pipelines';
const handlers = createPipelineRouteHandler({
manager,
storage,
pipeline: myPipelineConfig, // One pipeline per route
});
export const GET = handlers.GET;
export const POST = handlers.POST;
That's it! Your pipeline API is ready at /api/pipeline/my-pipeline.
API Endpoints
Each route handles one pipeline. The URL determines which pipeline to use.
POST /api/pipeline/my-pipeline
Start a new pipeline or return existing one.
Request body:
{
input: unknown; // Input data
jobOptions?: Record<string, unknown>; // Optional job options
}
Example:
const response = await fetch('/api/pipeline/my-pipeline', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
input: {
url: 'https://api.example.com/data',
userId: 'user-123',
},
jobOptions: {
'fetch-data': { timeout: 10000 },
},
}),
});
const result = await response.json();
// { success: true, data: { pipelineId: "abc123", isNew: true } }
GET /api/pipeline/my-pipeline?action=status&id=:id
Get current pipeline status.
Example:
const response = await fetch('/api/pipeline/my-pipeline?action=status&id=abc123');
const { data } = await response.json();
// { status: "processing", currentJobIndex: 1, totalJobs: 4, stages: [...] }
GET /api/pipeline/my-pipeline?action=result&id=:id[&jobName=:name]
Get a job result (artifact). If jobName is not provided, returns the last job result.
Example:
// Last job result
const response = await fetch('/api/pipeline/my-pipeline?action=result&id=abc123');
const { data } = await response.json();
// { pipelineId: "abc123", jobName: "save-result", status: "done", artifact: {...} }
// Result by job name
const response2 = await fetch('/api/pipeline/my-pipeline?action=result&id=abc123&jobName=fetch-data');
const { data: jobResult } = await response2.json();
// { pipelineId: "abc123", jobName: "fetch-data", status: "done", artifact: {...} }
Debug Endpoints
The following endpoints return sensitive data (input, options, artifacts) and are disabled by default. To enable them, set enableDebugEndpoints: true.
⚠️ WARNING: Do not enable in production unless you have proper authentication/authorization!
GET /api/pipeline/my-pipeline?action=job&id=:id&jobName=:name
Get detailed job data including input and options.
Example:
const response = await fetch('/api/pipeline/my-pipeline?action=job&id=abc123&jobName=fetch-data');
const { data } = await response.json();
// { name: "fetch-data", status: "done", input: {...}, options: {...}, artifact: {...} }
GET /api/pipeline/my-pipeline?action=pipeline&id=:id
Get full pipeline state.
Example:
const response = await fetch('/api/pipeline/my-pipeline?action=pipeline&id=abc123');
const { data } = await response.json();
// Full PipelineState object
GET /api/pipeline/my-pipeline?action=list
Get paginated list of pipelines of this type.
Query parameters:
page- Page number (default: 1)limit- Items per page (default: 10, max: 100)
Example:
const response = await fetch('/api/pipeline/my-pipeline?action=list&page=1&limit=10');
const { data } = await response.json();
// { items: [...], total: 50, page: 1, limit: 10, totalPages: 5 }
With MongoDB Storage
For production, use MongoDB storage:
// lib/neuroline.ts
import mongoose from 'mongoose';
import { PipelineManager, MongoPipelineStorage, PipelineSchema } from 'neuroline';
import { myPipelineConfig } from './pipelines';
// Connect to MongoDB
await mongoose.connect(process.env.MONGODB_URI!);
// Create model
const PipelineModel = mongoose.model('Pipeline', PipelineSchema);
// Create manager
const storage = new MongoPipelineStorage(PipelineModel);
export const manager = new PipelineManager({ storage });
manager.registerPipeline(myPipelineConfig);
Client-Side Usage
Use neuroline/client for client-side integration. One client per pipeline:
'use client';
import { useMemo, useState, useCallback } from 'react';
import { PipelineClient } from 'neuroline/client';
export function PipelineDemo() {
// Client URL points to specific pipeline route
const client = useMemo(() => new PipelineClient({ baseUrl: '/api/pipeline/my-pipeline' }), []);
const [status, setStatus] = useState(null);
const [isRunning, setIsRunning] = useState(false);
const handleStart = useCallback(async () => {
setIsRunning(true);
const { pipelineId, stop, completed } = await client.startAndPoll(
{
input: { url: 'https://api.example.com/data' },
},
(event) => setStatus(event.status),
(error) => console.error(error),
);
await completed;
setIsRunning(false);
}, [client]);
return (
<div>
<button onClick={handleStart} disabled={isRunning}>
Start Pipeline
</button>
{status && (
<div>
Status: {status.status}
{status.currentJobName && ` - ${status.currentJobName}`}
</div>
)}
</div>
);
}
Configuration Options
createPipelineRouteHandler({
manager: PipelineManager, // Required - pipeline manager instance
storage: PipelineStorage, // Required - storage for job details and list
pipeline: PipelineConfig, // Required - pipeline config for this route
enableDebugEndpoints: false, // Optional - enable action=job and action=pipeline (default: false)
});
Enabling Debug Endpoints
For development or internal tools, you can enable debug endpoints:
const handlers = createPipelineRouteHandler({
manager,
storage,
pipeline: myPipeline,
enableDebugEndpoints: process.env.NODE_ENV === 'development',
});
Error Handling
The handler automatically returns appropriate HTTP status codes:
200- Success400- Bad request (invalid input)404- Pipeline not found500- Internal server error
All errors return JSON format:
{
"error": "Error message"
}
Serverless Deployment
This package is fully compatible with serverless deployments (Vercel, Netlify, etc.):
// Use MongoDB or external storage
// In-memory storage will not persist across function invocations
const storage = new MongoPipelineStorage(PipelineModel);
const manager = new PipelineManager({ storage });
API Reference
createPipelineRouteHandler(options)
Creates GET and POST handlers for Next.js App Router.
Parameters:
manager: PipelineManager- Required. The pipeline manager instance.storage: PipelineStorage- Required. Storage for job details and list operations.pipeline: PipelineConfig- Required. Pipeline config for this route.
Returns:
{
GET: (request: NextRequest) => Promise<Response>,
POST: (request: NextRequest) => Promise<Response>
}
Multiple Pipelines
Create separate routes for each pipeline:
app/
api/
pipeline/
my-pipeline/
route.ts → handles /api/pipeline/my-pipeline
another/
route.ts → handles /api/pipeline/another
Each route exports handlers for its specific pipeline.
Individual Handlers
You can also use individual handlers for custom routing:
import {
handleStartPipeline,
handleGetStatus,
handleGetResult,
handleGetJob,
handleGetPipeline,
handleGetList,
} from 'neuroline-nextjs';
License
UNLICENSED
neuroline-nextjs
Интеграция с Next.js App Router для Neuroline - предоставляет обработчик и маршрутов для API.
Установка
yarn add neuroline neuroline-nextjs
Возможности
- Поддержка App Router - нативная интеграция с Next.js 14+ App Router
- Типобезопасные обработчики - полная поддержка TypeScript с NextRequest/Response
- Один route = один pipeline - каждый маршрут обрабатывает ровно один тип pipeline
- API деталей job - получение input, options и артефактов для отдельных jobs
- Stateless дизайн - работает с serverless деплоями
Быстрый старт
1. Создайте Pipeline Manager
// lib/neuroline.ts
import { PipelineManager, InMemoryPipelineStorage } from 'neuroline';
const storage = new InMemoryPipelineStorage();
export const manager = new PipelineManager({ storage });
export { storage };
2. Создайте обработчик API маршрута
Создайте отдельный маршрут для каждого pipeline. Например app/api/pipeline/my-pipeline/route.ts:
import { createPipelineRouteHandler } from 'neuroline-nextjs';
import { manager, storage } from '@/lib/neuroline';
import { myPipelineConfig } from '@/pipelines';
const handlers = createPipelineRouteHandler({
manager,
storage,
pipeline: myPipelineConfig, // Один pipeline на route
});
export const GET = handlers.GET;
export const POST = handlers.POST;
Готово! Ваш pipeline API доступен по адресу /api/pipeline/my-pipeline.
API Эндпоинты
Каждый route обрабатывает один pipeline. URL определяет какой pipeline использовать.
POST /api/pipeline/my-pipeline
Запустить новый pipeline или вернуть существующий.
Тело запроса:
{
input: unknown; // Входные данные
jobOptions?: Record<string, unknown>; // Опционально: опции для jobs
}
Пример:
const response = await fetch('/api/pipeline/my-pipeline', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
input: {
url: 'https://api.example.com/data',
userId: 'user-123',
},
jobOptions: {
'fetch-data': { timeout: 10000 },
},
}),
});
const result = await response.json();
// { success: true, data: { pipelineId: "abc123", isNew: true } }
GET /api/pipeline/my-pipeline?action=status&id=:id
Получить текущий статус pipeline.
Пример:
const response = await fetch('/api/pipeline/my-pipeline?action=status&id=abc123');
const { data } = await response.json();
// { status: "processing", currentJobIndex: 1, totalJobs: 4, stages: [...] }
GET /api/pipeline/my-pipeline?action=result&id=:id[&jobName=:name]
Получить результат (артефакт) job. Если jobName не передан, возвращается результат последней job.
Пример:
// Результат последней job
const response = await fetch('/api/pipeline/my-pipeline?action=result&id=abc123');
const { data } = await response.json();
// { pipelineId: "abc123", jobName: "save-result", status: "done", artifact: {...} }
// Результат по имени job
const response2 = await fetch('/api/pipeline/my-pipeline?action=result&id=abc123&jobName=fetch-data');
const { data: jobResult } = await response2.json();
// { pipelineId: "abc123", jobName: "fetch-data", status: "done", artifact: {...} }
Debug-эндпоинты
Следующие эндпоинты возвращают чувствительные данные (input, options, artifacts) и отключены по умолчанию. Для включения установите enableDebugEndpoints: true.
⚠️ ВНИМАНИЕ: Не включайте в production без надлежащей аутентификации/авторизации!
GET /api/pipeline/my-pipeline?action=job&id=:id&jobName=:name
Получить детальные данные job включая input и options.
Пример:
const response = await fetch('/api/pipeline/my-pipeline?action=job&id=abc123&jobName=fetch-data');
const { data } = await response.json();
// { name: "fetch-data", status: "done", input: {...}, options: {...}, artifact: {...} }
GET /api/pipeline/my-pipeline?action=pipeline&id=:id
Получить полное состояние pipeline.
Пример:
const response = await fetch('/api/pipeline/my-pipeline?action=pipeline&id=abc123');
const { data } = await response.json();
// Полный объект PipelineState
GET /api/pipeline/my-pipeline?action=list
Получить пагинированный список pipelines этого типа.
Query-параметры:
page- Номер страницы (по умолчанию: 1)limit- Элементов на странице (по умолчанию: 10, макс: 100)
Пример:
const response = await fetch('/api/pipeline/my-pipeline?action=list&page=1&limit=10');
const { data } = await response.json();
// { items: [...], total: 50, page: 1, limit: 10, totalPages: 5 }
С MongoDB хранилищем
Для продакшена используйте MongoDB:
// lib/neuroline.ts
import mongoose from 'mongoose';
import { PipelineManager, MongoPipelineStorage, PipelineSchema } from 'neuroline';
import { myPipelineConfig } from './pipelines';
// Подключение к MongoDB
await mongoose.connect(process.env.MONGODB_URI!);
// Создание модели
const PipelineModel = mongoose.model('Pipeline', PipelineSchema);
// Создание manager
const storage = new MongoPipelineStorage(PipelineModel);
export const manager = new PipelineManager({ storage });
manager.registerPipeline(myPipelineConfig);
Использование на клиенте
Используйте neuroline/client для клиентской интеграции. Один клиент на pipeline:
'use client';
import { useMemo, useState, useCallback } from 'react';
import { PipelineClient } from 'neuroline/client';
export function PipelineDemo() {
// URL клиента указывает на конкретный route pipeline
const client = useMemo(() => new PipelineClient({ baseUrl: '/api/pipeline/my-pipeline' }), []);
const [status, setStatus] = useState(null);
const [isRunning, setIsRunning] = useState(false);
const handleStart = useCallback(async () => {
setIsRunning(true);
const { pipelineId, stop, completed } = await client.startAndPoll(
{
input: { url: 'https://api.example.com/data' },
},
(event) => setStatus(event.status),
(error) => console.error(error),
);
await completed;
setIsRunning(false);
}, [client]);
return (
<div>
<button onClick={handleStart} disabled={isRunning}>
Запустить Pipeline
</button>
{status && (
<div>
Статус: {status.status}
{status.currentJobName && ` - ${status.currentJobName}`}
</div>
)}
</div>
);
}