Skip to content

orchestrate-solutions/modulink-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ModuLink JavaScript Library

Version License Node ES Modules

A modern JavaScript library for building modular applications with unified processing for HTTP, cron jobs, CLI commands, and message handling. Built on a hybrid architecture that combines clean function-based chains with flexible integration patterns.

✨ What Makes ModuLink Special

  • πŸ”— Hybrid Architecture: Clean function chains + flexible integration patterns
  • 🎯 Auto-Detection: Automatically detects single vs two-parameter connect patterns
  • 🧬 Universal Patterns: Same approach for HTTP, cron, CLI, standalone scripts
  • ⚑ Modern JavaScript: ES modules, async/await, and clean APIs
  • πŸ›‘οΈ Built-in Error Handling: Graceful error propagation and recovery
  • πŸ”§ Powerful Middleware: Observable middleware system for logging, timing, and monitoring
  • πŸ“¦ Zero Configuration: Works with or without web frameworks

πŸ—οΈ Core Architecture

ModuLink combines Business Logic (chains) with Integration (ModuLink instances):

Business Logic Layer

Type Purpose Example
Ctx Context object passed between functions { user: { id: 123 }, data: {...} }
Link Pure function with single responsibility validateUser, saveData, sendEmail
Chain Sequence of links with middleware support chain(validate, process, respond)

Integration Layer

Type Purpose Example
ModuLink Integration instance with middleware createModuLink(app)
Connect Flexible wiring with auto-detection modulink.connect(fn)
Triggers Event sources (HTTP, cron, CLI) Routes, schedules, commands

πŸš€ Quick Start

Installation

npm install modulink-js

Flexible Connect Patterns

ModuLink auto-detects your preferred pattern based on function arity:

import { chain, createModuLink } from 'modulink-js';
import express from 'express';

const app = express();
const modulink = createModuLink(app);

// Two-parameter pattern: fn(app, modulink)
modulink.connect((app, modu) => {
  app.get('/health', (req, res) => {
    res.json({ status: 'ok' });
  });
});

// Single-parameter pattern: fn(modulink) 
modulink.connect((modu) => {
  modu.app.get('/status', (req, res) => {
    res.json({ status: 'running' });
  });
});

// Standalone mode (no app framework)
const standalone = createModuLink();
standalone.connect((modu) => {
  // Process files, run CLI scripts, etc.
});

Business Logic with Chains

// Define pure business logic functions
const validateInput = (ctx) => {
  if (!ctx.body?.email) {
    return { ...ctx, error: new Error('Email is required') };
  }
  return { ...ctx, validated: true };
};

const processUser = async (ctx) => {
  if (ctx.error) return ctx;
  const user = await createUser(ctx.body);
  return { ...ctx, user };
};

const formatResponse = (ctx) => {
  if (ctx.error) {
    return { ...ctx, response: { error: ctx.error.message }, status: 400 };
  }
  return { ...ctx, response: { user: ctx.user }, status: 201 };
};

// Create processing chain
const userSignupChain = chain(validateInput, processUser, formatResponse);

// Connect to routes with either pattern
modulink.connect((app, modu) => {
  app.post('/api/signup', async (req, res) => {
    const ctx = modu.createContext({
      body: req.body,
      method: 'POST',
      path: '/api/signup'
    });
    
    const result = await userSignupChain(ctx);
    res.status(result.status || 200).json(result.response);
  });
});

πŸ”„ Five Usage Patterns

1. Web Framework Integration (Two-Parameter)

// Traditional pattern with explicit app access
modulink.connect((app, modu) => {
  app.get('/health', (req, res) => {
    res.json({ status: 'ok' });
  });
});

2. Web Framework Integration (Single-Parameter)

// Modern pattern using modu.app
modulink.connect((modu) => {
  modu.app.get('/status', (req, res) => {
    res.json({ status: 'running' });
  });
});

3. Standalone Scripts

// No app framework needed
const modulink = createModuLink();
modulink.connect((modu) => {
  const filename = process.argv[2];
  const ctx = modu.createContext({ filename, type: 'file-processing' });
  // Process files, CLI commands, etc.
});

4. Background Workers & Cron Jobs

// Scheduled tasks and background processing
modulink.connect((modu) => {
  modu.cron('0 0 * * *', async () => {
    const ctx = modu.createContext({ type: 'daily-cleanup' });
    await cleanupChain(ctx);
  });
});

5. Flexible Apps (Auto-Detection)

// Same code works with or without app
function setupModule(modulink) {
  // Works in both standalone and web modes
  if (modulink.app) {
    // Web-specific setup
    modulink.app.get('/api/status', handler);
  }
  // Always available: CLI, cron, etc.
  modulink.cli('status', statusChain);
}

modulink.connect(setupModule); // Auto-detects single parameter

πŸ”§ Middleware System

Instance-level middleware runs before chains:

// Add timing middleware
modulink.use(async (ctx, next) => {
  ctx.startTime = Date.now();
  await next();
  console.log(`Completed in ${Date.now() - ctx.startTime}ms`);
});

// Add logging middleware
modulink.use(async (ctx, next) => {
  console.log(`Processing: ${ctx.type || 'unknown'}`);
  await next();
});

// All chains now include this middleware automatically

🎯 Core Concepts

Immediate Execution Pattern

// Connect immediately executes the function
modulink.connect((modu) => {
  // This runs RIGHT NOW, not later
  console.log('Setting up routes...');
  
  modu.app.get('/ready', (req, res) => {
    res.json({ ready: true });
  });
});

Context Creation

// Create rich context objects
const ctx = modulink.createContext({
  userId: 123,
  requestId: 'req-456',
  type: 'user-update',
  startTime: Date.now()
});

// Context flows through entire chain
const result = await updateUserChain(ctx);

Error Propagation

// Errors flow naturally through chains
const safeChain = chain(
  (ctx) => ctx.error ? ctx : validateData(ctx),
  (ctx) => ctx.error ? ctx : processData(ctx),  
  (ctx) => ctx.error ? ctx : saveData(ctx)
);

// Or use built-in error handling
safeChain.use(errorHandler());

πŸ“š Examples

Check out the comprehensive examples:

  • examples/index-flexible.js - All connect patterns working together
  • examples/standalone-example.js - File processing without web framework
  • examples/connect-flexible.js - Helper functions for both patterns
  • docs/clean-chain-cookbook.md - Complete architectural guide

πŸ§ͺ Testing

Test business logic and integration separately:

// Test pure business logic
describe('validateInput', () => {
  test('should validate email', () => {
    const ctx = { body: { email: 'test@example.com' } };
    const result = validateInput(ctx);
    expect(result.validated).toBe(true);
  });
});

// Test integration patterns
describe('connect patterns', () => {
  test('should auto-detect single parameter', () => {
    const mockFn = jest.fn();
    modulink.connect(mockFn);
    expect(mockFn).toHaveBeenCalledWith(modulink);
  });
});

πŸ”— Key Benefits

  1. Function-First: Pure functions for business logic, instances for integration
  2. Auto-Detection: No need to remember which pattern to use
  3. Universal: Same patterns work everywhere (HTTP, CLI, cron, standalone)
  4. Flexible: Works with or without web frameworks
  5. Testable: Easy to test business logic and integration separately
  6. Observable: Built-in middleware for monitoring and debugging

πŸ“„ License

Apache License 2.0 - see LICENSE file for details.


ModuLink: Hybrid architecture for modern JavaScript applications. Clean function chains meet flexible integration patterns.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published