npm.io
0.2.1 • Published 8 months ago

flexible-core

Licence
ISC
Version
0.2.1
Deps
5
Size
530 kB
Vulns
0
Weekly
0

Flexible Core

npm version License: MIT

Event processing framework for Node.js that connects Event Sources to Frameworks through a flexible routing system.

Quick Start

npm install flexible-core flexible-http flexible-decorators
import "reflect-metadata";
import { FlexibleApp } from "flexible-core";
import { DecoratorsFrameworkModule, ExplicitControllerLoader } from "flexible-decorators";
import { HttpModule } from "flexible-http";
import { injectable } from "tsyringe";

@injectable()
@Controller()
export class HelloController {
    @Route(HttpGet)
    public world(): any {
        return { message: "Hello, World!" };
    }
}

const app = FlexibleApp.builder()
    .addEventSource(HttpModule.builder().withPort(3000).build())
    .addFramework(DecoratorsFrameworkModule.builder()
        .withControllerLoader(new ExplicitControllerLoader([HelloController]))
        .build())
    .createApp();

app.run();

→ Full Getting Started Guide

Features

  • High Performance - O(log n) routing with decision tree
  • Modular - Compose event sources, frameworks, and middleware
  • Timeout & Cancellation - Built-in support for request timeouts and client disconnections
  • Structured Logging - Built-in support with JSON output
  • Dependency Injection - Powered by TSyringe with child container support
  • Testable - Built-in test utilities
  • Extensible - Create custom event sources, frameworks, and loggers
  • TypeScript - Full type safety

Documentation

Getting Started
Architecture
Guides

Available Packages

Event Sources
  • flexible-http - HTTP/HTTPS server
  • Create your own by implementing FlexibleEventSource
Frameworks
  • flexible-decorators - Decorator-based controllers
  • Create your own by implementing FlexibleFramework
Examples

Core Concepts

┌─────────────────┐
│  Event Source   │  HTTP, WebSocket, Queue, etc.
└────────┬────────┘
         │ Events
         ▼
┌─────────────────┐
│     Router      │  Decision Tree (O(log n))
└────────┬────────┘
         │ Matched Routes
         ▼
┌─────────────────┐
│   Framework     │  Decorators, Express-like, etc.
└────────┬────────┘
         │ Middleware Pipeline
         ▼
┌─────────────────┐
│  Your Handler   │  Controller, Function, etc.
└─────────────────┘

→ Learn More About Architecture

Key Features

Timeout and Cancellation Support

Protect your application from long-running operations and handle client disconnections gracefully:

import { TimeoutMiddleware, CancellationMiddleware } from "flexible-core";
import { Controller, Route, BeforeExecution } from "flexible-decorators";
import { HttpGet } from "flexible-http";

@Controller()
export class UserController {
    @BeforeExecution(TimeoutMiddleware, 'processEvent', {
        config: { timeout: 5000 }  // 5 second timeout
    })
    @BeforeExecution(CancellationMiddleware, 'processEvent')
    @Route(HttpGet)
    public async getUsers() {
        // Protected by timeout and cancellation
        return await this.userService.fetchUsers();
    }
}

Features:

  • Composable timeout layers with different durations
  • Automatic cancellation on client disconnect
  • Built-in error types for consistent handling
  • Structured logging for timeout and cancellation events

→ Timeout and Cancellation Guide

Structured Logging
import { FlexibleLogger, FLEXIBLE_APP_TYPES } from "flexible-core";
import { inject, injectable } from "tsyringe";

@injectable()
@Controller()
export class UserController {
    constructor(@inject(FLEXIBLE_APP_TYPES.LOGGER) private logger: FlexibleLogger) {}

    @Route(HttpPost)
    public createUser(user: User): any {
        this.logger.info("Creating user", {
            username: user.username,
            timestamp: new Date().toISOString()
        });
        return { success: true };
    }
}

→ Logging Guide

High-Performance Routing

Decision tree-based router with O(log n) lookup:

// Automatically routes to the right handler
GET /users/123UserController.getUser()
POST /users       → UserController.createUser()
GET /posts/456PostController.getPost()

→ Routing Guide

Dependency Injection

Built on TSyringe for powerful DI with child container support:

import { inject, injectable } from "tsyringe";

@injectable()
@Controller()
export class UserController {
    constructor(
        @inject(FLEXIBLE_APP_TYPES.LOGGER) private logger: FlexibleLogger,
        @inject(UserService.TYPE) private userService: UserService
    ) {}
}
Child Containers for Composable Architecture

Create isolated layers with shared dependencies:

import { FlexibleContainer } from "flexible-core";

// Main container with shared bindings
const mainContainer = new FlexibleContainer();
mainContainer.registerValue(FLEXIBLE_APP_TYPES.LOGGER, logger);

// Security layer with child container
const securityContainer = mainContainer.createChild();
securityContainer.registerValue("NextLayer", businessEventSource);

const securityApp = FlexibleApp.builder()
    .withContainer(securityContainer)
    .addEventSource(httpModule)
    .addFramework(securityFramework)
    .createApp();

// Business layer with child container
const businessContainer = mainContainer.createChild();

const businessApp = FlexibleApp.builder()
    .withContainer(businessContainer)
    .addEventSource(businessEventSource)
    .addFramework(businessFramework)
    .createApp();

Benefits:

  • Each layer can override shared bindings
  • True isolation between layers
  • Shared bindings automatically available
  • No pollution of parent container
Modular Design

Everything is a module that can be composed:

const app = FlexibleApp.builder()
    .withLogger(loggerModule)      // Optional logging
    .addEventSource(httpModule)    // HTTP events
    .addEventSource(wsModule)      // WebSocket events
    .addFramework(decoratorModule) // Decorator framework
    .createApp();
Container Management

Use TSyringe's powerful DI with flexible-core's container wrapper:

import { FlexibleContainer } from "flexible-core";

// Create container with shared services
const container = new FlexibleContainer();
container.registerClass(UserService.TYPE, UserService);
container.registerValue(FLEXIBLE_APP_TYPES.LOGGER, logger);

// Use container in app
const app = FlexibleApp.builder()
    .withContainer(container)
    .addEventSource(httpModule)
    .addFramework(decoratorModule)
    .createApp();

Examples

Basic HTTP Server
const app = FlexibleApp.builder()
    .addEventSource(HttpModule.builder().withPort(3000).build())
    .addFramework(DecoratorsFrameworkModule.builder()
        .withControllerLoader(new ExplicitControllerLoader([HelloController]))
        .build())
    .createApp();

await app.run();
With Logging
import { ConsoleLoggerModule } from "flexible-core";

const app = FlexibleApp.builder()
    .withLogger(new ConsoleLoggerModule())
    .addEventSource(httpEventSource)
    .addFramework(decoratorsFramework)
    .createApp();
Production Configuration
import { ConfigurableLoggerModule, LogLevel } from "flexible-core";

const app = FlexibleApp.builder()
    .withLogger(new ConfigurableLoggerModule({
        minLevel: LogLevel.INFO,
        format: 'json',
        includeTimestamp: true
    }))
    .addEventSource(httpEventSource)
    .addFramework(decoratorsFramework)
    .createApp();

→ More Examples

Testing

Flexible includes built-in test utilities:

import { DummyFramework, DummyEventSource } from "flexible-core";

const framework = new DummyFramework();
framework.addPipelineDefinition({
    filterStack: [/* ... */],
    middlewareStack: [/* ... */]
});

const eventSource = new DummyEventSource();
await eventSource.run();
await eventSource.generateEvent(myEvent);

→ Testing Guide

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

MIT Federico Tacchini


Made with by the Flexible team