An unopinionated, event driven, pluggable, server/less framework.
Ingest is a lightweight, flexible server framework that brings the familiar Express.js-like API to serverless environments. Built on top of the powerful @stackpress/lib event system, Ingest provides a unified approach to building applications that can run anywhere - from traditional Node.js servers to serverless platforms like AWS Lambda, Vercel, and Netlify.
- 🚀 Serverless-First: Designed specifically for serverless environments while maintaining compatibility with traditional servers
- 🔄 Event-Driven: Built on a robust event system that enables reactive programming patterns
- 🛣️ Multi-Routing Interface: Four different routing approaches in one framework
- 🔌 Plugin System: Highly extensible with a simple plugin architecture
- 📦 Build Support: Exposes routing information for bundlers and build tools
- 🌐 Cross-Platform: Works with Node.js HTTP, WHATWG Fetch, and various serverless platforms
npm install @stackpress/ingest # or yarn add @stackpress/ingestimport { server } from '@stackpress/ingest/http'; const app = server(); // Traditional Express-like routing app.get('/', (req, res) => { res.setHTML('<h1>Hello World!</h1>'); }); app.get('/api/users/:id', (req, res) => { const userId = req.data.get('id'); res.setJSON({ id: userId, name: 'John Doe' }); }); // Start the server app.create().listen(3000, () => { console.log('Server running on port 3000'); });import { server } from '@stackpress/ingest/whatwg'; const app = server(); app.get('/api/hello', (req, res) => { res.setJSON({ message: 'Hello from Vercel!' }); }); export default async function handler(request: Request) { return await app.handle(request, new Response()); }Ingest provides four different ways to define routes, giving you flexibility in how you organize your application:
Express.js-like inline route handlers:
app.action.get('/users', (req, res) => { res.setJSON({ users: [] }); });Route to files that export default handlers:
app.entry.get('/users', './routes/users.js');Dynamic imports for code splitting:
app.import.get('/users', () => import('./routes/users.js'));Direct template rendering:
app.view.get('/users', './views/users.hbs');Ingest can automatically determine which router to use based on your input:
// Automatically uses action router app.get('/users', (req, res) => { /* handler */ }); // Automatically uses import router app.get('/users', () => import('./routes/users.js')); // Automatically uses view router app.get('/users', './views/users.hbs');Ingest features a powerful plugin system that allows you to modularize your application:
// src/plugins/auth.ts export default function authPlugin(server) { server.on('request', (req, res) => { // Add authentication logic if (!req.headers.get('authorization')) { res.setError('Unauthorized', {}, [], 401); return false; // Stop processing } }); }Add plugins to your package.json:
{ "plugins": [ "./src/plugins/auth", "./src/plugins/logging", "@my-org/ingest-plugin" ] }import { server } from '@stackpress/ingest/http'; const app = server(); // Load all plugins await app.bootstrap(); app.create().listen(3000);Ingest is built on a powerful event system that allows for reactive programming:
// Listen to all requests app.on('request', (req, res) => { console.log(`${req.method} ${req.url.pathname}`); }); // Listen to specific routes app.on('GET /api/users', (req, res) => { // This runs for GET /api/users }); // Priority-based listeners app.on('request', middleware1, 10); // Higher priority app.on('request', middleware2, 5); // Lower priorityimport { server } from '@stackpress/ingest/whatwg'; const app = server(); app.get('/api/hello', (req, res) => { res.setJSON({ message: 'Hello from Lambda!' }); }); export const handler = async (event, context) => { const request = new Request(event.requestContext.http.sourceIp); const response = new Response(); return await app.handle(request, response); };import { server } from '@stackpress/ingest/whatwg'; const app = server(); app.get('/api/users', (req, res) => { res.setJSON({ users: [] }); }); export default async function handler(req: Request) { return await app.handle(req, new Response()); }import { server } from '@stackpress/ingest/whatwg'; const app = server(); app.get('/.netlify/functions/api', (req, res) => { res.setJSON({ message: 'Hello from Netlify!' }); }); export const handler = async (event, context) => { const request = new Request(event.rawUrl); const response = new Response(); return await app.handle(request, response); };Ingest exposes routing information that can be used by bundlers and build tools:
const app = server(); app.get('/users', () => import('./routes/users.js')); app.get('/posts', () => import('./routes/posts.js')); // Access routing information console.log(app.routes); // Route definitions console.log(app.imports); // Dynamic imports console.log(app.entries); // File entries console.log(app.views); // View templatesThis information can be used by bundlers to:
- Pre-bundle route modules
- Generate static route manifests
- Optimize code splitting
- Create deployment artifacts
- API Reference - Complete API documentation
- Examples - Comprehensive usage examples
- Plugin Development - Guide to creating plugins
Check out the examples/ directory for complete working examples:
with-http- Basic HTTP serverwith-vercel- Vercel deploymentwith-lambda- AWS Lambda deploymentwith-netlify- Netlify deploymentwith-plugins- Plugin system usagewith-handlebars- Template engine integration