npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, πŸ‘‹, I’m Ryan HefnerΒ  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you πŸ™

Β© 2026 – Pkg Stats / Ryan Hefner

syntrojs

v0.8.0

Published

πŸ”₯ DUAL RUNTIME: FastAPI for Node.js AND Bun - Same Code, Maximum Performance | ⚑ 3.8x Faster with Bun

Readme

npm version πŸš€ DUAL RUNTIME ⚑ Bun Performance πŸš€ Node.js Performance Coverage Tests


πŸš€ Status: Production Ready (Pre-1.0)

βœ… SyntroJS is production-ready with a battle-tested core and comprehensive feature set. The framework is stable and ready for production use.

  • βœ… Battle-tested Core - 980+ tests across Node.js and Bun (100% passing)
  • βœ… CORS Fully Functional - REST and Lambda modes with comprehensive validation
  • βœ… AWS Lambda Support - Production-ready Lambda mode with full API Gateway integration
  • βœ… Router System - Group routes with prefixes and router-level middleware
  • βœ… Type-Safe Client - Testing and frontend integration with autocomplete
  • βœ… Active development - Regular updates and bug fixes
  • 🎯 v0.8.0 planned - Security & Real-time Features

Latest Release: v0.8.0 - Security Features (CSRF, JWT Refresh) + Real-time (SSE) - CHANGELOG


🎯 What is SyntroJS?

SyntroJS is the world's first dual-runtime framework that brings the simplicity and developer experience of FastAPI to the TypeScript ecosystem. Write your code once and run it on either Node.js for stability or Bun for maximum performance.

Key Highlights:

  • πŸš€ Dual Runtime: Same code runs on Node.js and Bun
  • ☁️ AWS Lambda: Same code works in REST (dev) and Lambda (prod) modes
  • πŸ”₯ FastAPI DX: Automatic validation, type safety, elegant error handling
  • 🎨 Auto Docs: Interactive Swagger UI + ReDoc out of the box
  • πŸ§ͺ Testing: SmartMutator for mutation testing in seconds

πŸš€ Quick Start

Installation

npm install syntrojs zod

Basic REST API

import { SyntroJS } from 'syntrojs';
import { z } from 'zod';

const app = new SyntroJS({ title: 'My API' });

// Simple GET endpoint
app.get('/hello', { 
  handler: () => ({ message: 'Hello World!' }) 
});

// POST with automatic validation
app.post('/users', {
  body: z.object({
    name: z.string().min(1),
    email: z.string().email(),
  }),
  handler: ({ body }) => ({ id: 1, ...body }),
});

await app.listen(3000);

That's it! πŸŽ‰ Visit http://localhost:3000/docs for interactive documentation.

AWS Lambda Mode

Same code, Lambda deployment - Just change one flag:

import { SyntroJS } from 'syntrojs';
import { z } from 'zod';

// Lambda mode: rest: false
const app = new SyntroJS({ rest: false, title: 'My API' });

app.post('/users', {
  body: z.object({
    name: z.string().min(1),
    email: z.string().email(),
  }),
  handler: ({ body }) => ({ id: 1, ...body }),
});

// Export handler for AWS Lambda
export const handler = app.handler();

That's it! πŸŽ‰ Deploy to AWS Lambda. Same validation, same type safety, same code.

See Lambda Usage Guide for complete examples.


✨ Key Features

πŸš€ Dual Runtime Support

Write once, run on both Node.js and Bun. Zero code changes required.

☁️ AWS Lambda Support

Same code works in REST mode (development) and Lambda mode (production). Just set rest: false. Full API Gateway integration with automatic event detection and CORS support.

Lambda Adapters Status:

  • βœ… API Gateway: Implemented
  • βœ… SQS: Implemented
  • βœ… S3: Implemented
  • βœ… EventBridge: Implemented

πŸ”₯ FastAPI-like Developer Experience

Automatic validation with Zod, full TypeScript type safety, elegant error handling (HTTPException).

🎨 Automatic Interactive Docs

Beautiful landing page + Swagger UI + ReDoc out of the box at /docs.

πŸ§ͺ Testing Superpower

SmartMutator for mutation testing in seconds. Type-safe client for testing and frontend integration.

πŸ”Œ Rich Ecosystem

Middleware system, WebSockets, dependency injection, background tasks, structured logging.

πŸ”’ Security First

JWT, OAuth2, API Keys, and security plugins built-in.

πŸ—οΈ Extensible Architecture

Lambda adapters follow SOLID principles and can be extracted to separate packages. Test adapters independently without full framework.


πŸ“š Examples

We have comprehensive examples in the examples/ directory:

Getting Started

Features

Advanced

See All Examples

Check the examples README for a complete list.


πŸ”₯ Dual-Runtime: Node.js vs Bun

Same code, different runtimes:

# Node.js (stability + full ecosystem)
node app.js

# Bun (maximum performance)
bun app.js

| Runtime | Performance | Tests Passing | Use Case | |---------|-------------|---------------|----------| | Node.js | 89.5% of Fastify (5,819 req/s) | 728/728 (100%) | Production, plugins | | Bun | 3.8x faster (~22,000 req/s) | 458/487 (94%) | Maximum speed |

Bun Limitations

| Feature | Node.js | Bun | Status | |---------|---------|-----|--------| | Core API | βœ… Full | βœ… Full | Identical | | Plugins (CORS, Helmet, etc.) | βœ… Full | βœ… Full | Production ready | | Static files | βœ… Full | ❌ Not available | v0.9.0 planned | | getRawFastify() | βœ… Works | ❌ Use getRawServer() | - |


πŸ’‘ Core Concepts

Request Validation

Automatic validation with Zod schemas:

app.post('/users', {
  body: z.object({
    name: z.string().min(1),
    email: z.string().email(),
  }),
  params: z.object({
    id: z.string().uuid(),
  }),
  query: z.object({
    page: z.coerce.number().min(1).default(1),
  }),
  handler: ({ body, params, query }) => {
    // All validated and type-safe!
    return { ...body, id: params.id, page: query.page };
  },
});

Dependency Injection

Share services across routes:

import { inject } from 'syntrojs';

const dbService = inject(() => new Database(), { scope: 'singleton' });

app.get('/users', {
  dependencies: { db: dbService },
  handler: ({ dependencies }) => dependencies.db.getUsers()
});

Error Handling

FastAPI-style exceptions:

import { NotFoundException, BadRequestException } from 'syntrojs';

app.get('/users/:id', {
  handler: ({ params }) => {
    const user = findUser(params.id);
    if (!user) {
      throw new NotFoundException('User not found');
    }
    return user;
  },
});

Middleware

Global or path-specific:

// Global middleware
app.use(async (ctx, next) => {
  console.log(`${ctx.method} ${ctx.path}`);
  await next();
});

// Path-specific
app.use('/api/*', async (ctx, next) => {
  if (!ctx.headers.authorization) {
    throw new UnauthorizedException('Token required');
  }
  await next();
});

Background Tasks

Non-blocking async tasks:

app.post('/users', {
  handler: ({ body, background }) => {
    // Queue email send (non-blocking)
    background.addTask(async () => {
      await sendWelcomeEmail(body.email);
    });
    
    return { success: true };
  }
});

πŸ“– API Reference

Creating an Application

new SyntroJS(config?: SyntroJSConfig)

Configuration Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | title | string | - | API title for OpenAPI docs | | version | string | - | API version | | description | string | - | API description | | runtime | 'auto' \| 'node' \| 'bun' | 'auto' | Force specific runtime | | rest | boolean | true | REST mode (HTTP server) or Lambda mode | | docs | boolean \| object | true | Configure documentation endpoints | | logger | boolean | false | Enable Fastify logger | | syntroLogger | boolean \| object | false | Enable @syntrojs/logger |

Route Registration

app.get(path: string, config: RouteConfig)
app.post(path: string, config: RouteConfig)
app.put(path: string, config: RouteConfig)
app.delete(path: string, config: RouteConfig)
app.patch(path: string, config: RouteConfig)

Route Config:

interface RouteConfig {
  handler: (ctx: RequestContext) => any;
  body?: ZodSchema;        // Request body validation
  params?: ZodSchema;      // Path parameters validation
  query?: ZodSchema;       // Query parameters validation
  response?: ZodSchema;    // Response validation
  status?: number;         // Default status code
  dependencies?: object;   // Dependency injection
}

Server Management

REST Mode:

// Start server
const address = await app.listen(port: number, host?: string);

// Stop server
await app.close();

Lambda Mode:

// Export handler
export const handler = app.handler();

Request Context

interface RequestContext {
  method: HttpMethod;              // HTTP method
  path: string;                    // Request path
  params: any;                     // Path parameters (validated)
  query: any;                      // Query parameters (validated)
  body: any;                       // Request body (validated)
  headers: Record<string, string>; // Request headers
  cookies: Record<string, string>; // Cookies
  correlationId: string;           // Request tracking ID
  timestamp: Date;                 // Request timestamp
  dependencies: Record<string, any>; // Injected dependencies
  background: {
    addTask(task: () => void): void; // Queue background task
  };
  download(data, options): FileDownloadResponse; // File download helper
  redirect(url, statusCode?): RedirectResponse;  // Redirect helper
  accepts: AcceptsHelper;          // Content negotiation helper
}

πŸ”’ Security

OAuth2 Password Bearer

import { OAuth2PasswordBearer } from 'syntrojs';

const oauth2 = new OAuth2PasswordBearer({ tokenUrl: '/token' });

app.get('/protected', {
  dependencies: { user: oauth2 },
  handler: ({ dependencies }) => ({ user: dependencies.user }),
});

HTTP Bearer

import { HTTPBearer } from 'syntrojs';

const bearer = new HTTPBearer();

app.get('/api/data', {
  dependencies: { token: bearer },
  handler: ({ dependencies }) => ({ data: 'protected' }),
});

API Key

import { APIKeyHeader, APIKeyQuery } from 'syntrojs';

// Via header
const apiKeyHeader = new APIKeyHeader({ name: 'X-API-Key' });

// Via query parameter
const apiKeyQuery = new APIKeyQuery({ name: 'api_key' });

app.get('/api/data', {
  dependencies: { apiKey: apiKeyHeader },
  handler: ({ dependencies }) => ({ data: 'protected' }),
});

HTTP Basic Auth

import { HTTPBasic } from 'syntrojs';

const basicAuth = new HTTPBasic();

app.get('/admin', {
  dependencies: { credentials: basicAuth },
  handler: ({ dependencies }) => {
    const { username, password } = dependencies.credentials;
    return { admin: true };
  },
});

πŸ§ͺ Testing

Standard Testing

import { describe, test, expect, beforeAll, afterAll } from 'vitest';
import { app } from './app';

describe('API Tests', () => {
  let server: string;
  
  beforeAll(async () => {
    server = await app.listen(0); // Random port
  });
  
  afterAll(async () => {
    await app.close();
  });

  test('POST /users creates a user', async () => {
    const port = new URL(server).port;
    const res = await fetch(`http://localhost:${port}/users`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: 'John', email: '[email protected]' })
    });
    
    const data = await res.json();
    expect(res.status).toBe(200);
    expect(data.name).toBe('John');
  });
});

Type-Safe Client

Test your API without starting a server, or use it in your frontend:

import { createClient } from 'syntrojs';
import type { App } from './app';

// Local mode (testing) - executes handlers directly
const client = createClient(app, { mode: 'local' });

// Call routes with autocomplete
const response = await client.users.get();
const user = await client.users[':id'].get({ params: { id: '123' } });
const created = await client.users.post({ 
  body: { name: 'John', email: '[email protected]' } 
});

// Remote mode (frontend) - makes HTTP requests
const apiClient = createClient(app, { 
  mode: 'remote', 
  baseUrl: 'https://api.example.com' 
});

See Type-Safe Client Documentation for complete examples.

SmartMutator - Mutation Testing

pnpm test:mutate

| Method | Mutants | Tests | Time | |--------|---------|-------|------| | Stryker (vanilla) | 1,247 | 187,050 | 43 min | | SmartMutator | 142 | 284 | 12 sec |

Mutation Score: 58.72% (742 killed, 144 survived)


πŸ“Š Quality Metrics

  • Tests: 1,019+ passing (Node.js 100%, Bun 94%)
  • Coverage: 71.55% (Branch: 80.73%)
  • Mutation Score: 58.72%
  • Code Quality: 100% SOLID + DDD + Functional Programming
  • Top Performers: RouteRegistry (100%), ZodAdapter (100%), DependencyInjector (95.83%)

πŸš€ Production & Security

const app = new SyntroJS({
  title: 'Production API',
  docs: false  // βœ… REQUIRED for production
});

Security Checklist

  • [ ] Disable all documentation (docs: false)
  • [ ] Set proper CORS origins (not *)
  • [ ] Enable rate limiting
  • [ ] Configure structured logging without sensitive data
  • [ ] Use environment variables for secrets

πŸ’Ž TOON Format (v0.5.0+)

Reduce API bandwidth costs 40-60% while keeping responses human-readable.

| Feature | JSON | TOON 🎯 | gRPC/Protobuf | |---------|------|------------|---------------| | Payload Size | 100% | 40-50% ⚑ | 35-45% | | Human-Readable | βœ… Yes | βœ… Yes | ❌ Binary | | Debug with curl | βœ… Easy | βœ… Easy | ❌ Requires tools | | Setup Time | 5 minutes | 5 minutes | 2+ hours | | Tooling Needed | None | None | protoc, plugins |

TOON gives you the best of both worlds: gRPC's efficiency with JSON's simplicity.

See TOON Format Documentation for details.


πŸ—ΊοΈ Roadmap

βœ… v0.4.0 - REST Completion (100% COMPLETE πŸŽ‰)

  • [x] File downloads, streaming, uploads
  • [x] HTTP redirects, content negotiation

βœ… v0.5.0 - TOON Format (100% COMPLETE πŸŽ‰)

  • [x] TOON Format Support (40-60% payload reduction)
  • [x] Serialization Architecture Refactor

βœ… v0.6.0 - AWS Lambda Support (100% COMPLETE πŸŽ‰)

  • [x] Lambda Mode (rest: false)
  • [x] API Gateway Integration
  • [x] Dynamic Routes with pattern matching
  • [x] 82 Lambda tests passing

βœ… v0.7.0 - Router + Advanced Middleware (100% COMPLETE πŸŽ‰)

  • [x] SyntroRouter - Group endpoints with prefixes
  • [x] Router-level middleware (router.use())
  • [x] app.include(router) - Include routers in app
  • [x] Type-Safe Client (createClient) - Testing & frontend integration
  • [x] Serializer Chain of Responsibility with next()
  • [x] Serializer Priority System
  • [x] Serializer Helper Methods (registerBefore, registerAfter, registerFirst)
  • [x] SyntroRouter - Group endpoints with prefixes
  • [x] Router-level middleware (router.use())
  • [x] app.include(router) - Include routers in app
  • [x] Type-Safe Client (createClient) - Testing & frontend integration
  • [x] Serializer Chain of Responsibility with next()
  • [x] Serializer Priority System
  • [x] Serializer Helper Methods (registerBefore, registerAfter, registerFirst)

🎨 v0.8.0 - Security & Real-time Features

  • [x] CSRF protection
  • [x] JWT Refresh Tokens
  • [x] Server-Sent Events (SSE)
  • [ ] WebSocket rooms/namespaces
  • [ ] Session management

🎨 v0.9.0 - Completeness (Optional Features)

  • [ ] Static file serving (optional)
  • [ ] Template rendering integrations (optional)
  • [ ] Native Bun plugins

πŸ—οΈ v1.0.0 - Production Ready

  • [ ] Official CLI (create-syntrojs)
  • [ ] Graceful shutdown
  • [ ] Complete documentation (Docusaurus)
  • [ ] Migration guides
  • [ ] Security audit

πŸ“š Documentation


🀝 Contributing

We welcome contributions! Check out our GitHub repository.

πŸ“„ License

Apache 2.0 - See LICENSE for details.