Skip to content

alialfredji/hook-app

Repository files navigation

hook-app

npm version License: ISC

A WordPress-style hooks system for Node.js applications. Build modular, traceable, and extensible apps with lifecycle hooks, services, and features.

Installation

npm install hook-app
import hookApp from 'hook-app';

Quick Start

Create a simple app with a feature that runs during initialization:

import hookApp, { type RegisterContext } from 'hook-app';

const myFeature = ({ registerAction }: RegisterContext) => {
  registerAction({
    hook: '$INIT_FEATURE',
    handler: () => {
      console.log('Hello, Hook App!');
    },
  });
};

await hookApp({ features: [myFeature] });

Core Concepts

Hooks

Named extension points where actions can attach. Reference built-in hooks with $HOOK_NAME syntax:

registerAction({
  hook: '$INIT_FEATURE',  // Built-in lifecycle hook
  handler: () => { /* ... */ },
});

Actions

Functions that execute when a hook is triggered. Actions have a name, priority, and handler:

registerAction({
  hook: '$START',
  name: 'my-action',
  priority: 10,  // Higher = runs first
  handler: (args, ctx) => {
    // Your logic here
  },
});

Services & Features

  • Services - Core integrations that set up shared functionality (databases, logging, etc.)
  • Features - Application-specific logic built on top of services

Both use the same RegisterContext interface:

const myService = ({ registerAction, registerHook, createHook }: RegisterContext) => {
  // Register custom hooks, actions, etc.
};

await hookApp({
  services: [myService],
  features: [myFeature],
});

Lifecycle

Boot phases execute in this order:

START → SETTINGS → INIT_SERVICES → INIT_SERVICE → INIT_FEATURES → INIT_FEATURE
      → START_SERVICES → START_SERVICE → START_FEATURES → START_FEATURE → FINISH

Key Patterns

Custom Hook Communication

Features communicate through custom hooks:

import hookApp, { type RegisterContext } from 'hook-app';

// Feature 1: Registers and triggers a custom hook
const notifier = ({ registerHook, registerAction, createHook }: RegisterContext) => {
  registerHook({ NOTIFY: 'notify' });

  registerAction({
    hook: '$INIT_FEATURE',
    handler: () => {
      createHook.sync('notify', { message: 'Hello from notifier!' });
    },
  });
};

// Feature 2: Listens to the custom hook
const listener = ({ registerAction }: RegisterContext) => {
  registerAction({
    hook: '$NOTIFY',
    handler: (args) => {
      console.log('Received:', (args as { message: string }).message);
    },
  });
};

await hookApp({ features: [notifier, listener] });

Settings & Configuration

Access and modify settings using dot-notation paths:

import hookApp, { type RegisterContext } from 'hook-app';

const app = await hookApp({
  settings: {
    api: {
      baseUrl: 'https://api.example.com',
      timeout: 5000,
    },
  },
  features: [
    ({ registerAction }: RegisterContext) => {
      registerAction({
        hook: '$INIT_FEATURE',
        handler: ({ getConfig, setConfig }: RegisterContext) => {
          const url = getConfig<string>('api.baseUrl');
          console.log('API URL:', url);

          // Modify settings
          setConfig('api.timeout', 10000);
        },
      });
    },
  ],
});

// Access final settings
console.log(app.settings);

Hook Execution Modes

Choose how actions execute when a hook is triggered:

Mode Method Description
sync createHook.sync(name, args?) Synchronous execution
serie createHook.serie(name, args?) Async, one at a time
parallel createHook.parallel(name, args?) Async, all at once
waterfall createHook.waterfall(name, initial) Pass result to next handler

Waterfall example:

registerAction('transform', (value: number) => value + 1);
registerAction('transform', (value: number) => value * 2);

const result = createHook.waterfall('transform', 5);
// result.value === 12  (5 + 1 = 6, then 6 * 2 = 12)

Lifecycle Hooks Reference

Hook Execution Description
$START serie App starting
$SETTINGS serie Configure settings
$INIT_SERVICES parallel Initialize all services
$INIT_SERVICE serie Initialize each service
$INIT_FEATURES parallel Initialize all features
$INIT_FEATURE serie Initialize each feature
$START_SERVICES parallel Start all services
$START_SERVICE serie Start each service
$START_FEATURES parallel Start all features
$START_FEATURE serie Start each feature
$FINISH serie App ready

API Quick Reference

Main Entry

import hookApp from 'hook-app';

const app = await hookApp({
  services?: ServiceDef[],
  features?: FeatureDef[],
  settings?: Record<string, unknown> | ((ctx: RegisterContext) => Record<string, unknown>),
  context?: Record<string, unknown>,
  trace?: string | null,
});

// Returns: { settings, context }

Registration (inside services/features)

// Register an action on a hook
registerAction({
  hook: '$INIT_FEATURE',
  handler: (args, ctx) => { /* ... */ },
  name?: string,
  priority?: number,
});

// Shorthand forms
registerAction('hook-name', handler);
registerAction('hook-name', handler, { priority: 10 });

// Register a custom hook
registerHook({ MY_HOOK: 'my-hook' });

Hook Execution

// Synchronous
const results = createHook.sync('hook-name', args?);

// Async sequential
const results = await createHook.serie('hook-name', args?);

// Async parallel
const results = await createHook.parallel('hook-name', args?);

// Waterfall (pass value through handlers)
const { value, results } = createHook.waterfall('hook-name', initialValue);

Config & Context Access

// Get/set configuration
const value = getConfig<T>('path.to.value', defaultValue?);
setConfig('path.to.value', newValue);

// Get/set custom context
const value = getContext<T>('path.to.value', defaultValue?);
setContext('path.to.value', newValue);

Tracing

Enable boot tracing to debug your app's lifecycle:

await hookApp({
  trace: 'compact',  // 'full' | 'normal' | 'compact' | null
  features: [/* ... */],
});

License

ISC

Links

About

hook-app is a dynamic framework designed to supercharge your Node.js applications. It offers a traceable, debuggable, and modular approach to build and manage your applications

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors