import { Handle, Position } from '@xyflow/react'
const METHOD_COLORS = {
GET: { bg: '#0d4429', color: '#4ade80' },
POST: { bg: '#172554', color: '#60a5fa' },
PUT: { bg: '#451a03', color: '#fb923c' },
PATCH: { bg: '#2e1065', color: '#c084fc' },
DELETE: { bg: '#450a0a', color: '#f87171' },
OPTIONS: { bg: '#1c1917', color: '#a8a29e' },
HEAD: { bg: '#1c1917', color: '#a8a29e' },
}
// Handles for LR layout: parent flows in from the LEFT, children exit to the RIGHT
const TARGET_HANDLE =
const SOURCE_HANDLE =
/**
* Unified handler node — three modes: ABSTRACT, CONCRETE, LAMBDA.
* Handles are Left (in) / Right (out) for Left-to-Right DAG layout.
*/
export default function HandlerNode({ data, selected }) {
// ── ABSTRACT ──────────────────────────────────────────────────────────
if (data.isAbstract) {
return (
{TARGET_HANDLE}
{SOURCE_HANDLE}
ABSTRACT
{data.name}
)
}
// ── LAMBDA ────────────────────────────────────────────────────────────
if (data.isLambda) {
const method = data.method || 'GET'
const path = data.path || '/'
const m = METHOD_COLORS[method] || METHOD_COLORS.OPTIONS
const pathHtml = path.replace(/\{([^}]+)\}/g, '{$1}')
return (
{TARGET_HANDLE}
{SOURCE_HANDLE}
LAMBDA
{method}
{data.middleware?.length > 0 && (
{data.middleware.map(mw => (
{mw}
))}
)}
)
}
// ── CONCRETE ──────────────────────────────────────────────────────────
return (
{TARGET_HANDLE}
{SOURCE_HANDLE}
{/* Header */}
{/* Routes */}
0 ? 8 : 0 }}>
{data.routes?.map((route, i) => {
const m = METHOD_COLORS[route.method] || METHOD_COLORS.OPTIONS
const pathHtml = (route.path || '/').replace(
/\{([^}]+)\}/g,
'
{$1}'
)
return (
{route.method}
)
})}
{/* Middleware */}
{data.middleware?.length > 0 && (
{data.middleware.map(mw => (
{mw}
))}
)}
)
}