Logos DX
    Preparing search index...

    Class HookEngine<Lifecycle, FailArgs>

    A lightweight, type-safe lifecycle hook system.

    HookEngine allows you to define lifecycle events and subscribe to them. Callbacks receive spread arguments with a context object as the last param.

    interface FetchLifecycle {
    beforeRequest(url: string, options: RequestInit): Promise<Response>;
    afterRequest(response: Response, url: string): Promise<Response>;
    }

    const hooks = new HookEngine<FetchLifecycle>();

    hooks.add('beforeRequest', (url, opts, ctx) => {
    ctx.args(url, { ...opts, headers: { ...opts.headers, 'X-Token': token } });
    });

    hooks.add('beforeRequest', (url, opts, ctx) => {
    const cached = cache.get(url);
    if (cached) return ctx.returns(cached);
    });

    const pre = await hooks.run('beforeRequest', url, options);
    if (pre.returned) return pre.result;
    const response = await fetch(...pre.args);

    Type Parameters

    • Lifecycle = DefaultLifecycle

      Interface defining the lifecycle hooks

    • FailArgs extends unknown[] = [string]

      Arguments type for ctx.fail() (default: [string])

    Index

    Constructors

    Methods

    • Subscribe to a lifecycle hook.

      Type Parameters

      • K extends string | number | symbol

      Parameters

      Returns () => void

      Cleanup function to remove the subscription

      // Simple callback
      const cleanup = hooks.add('beforeRequest', (url, opts, ctx) => {
      console.log('Request:', url);
      });

      // With options
      hooks.add('analytics', (event, ctx) => {
      track(event);
      }, { once: true, ignoreOnFail: true });

      // With priority (lower runs first)
      hooks.add('beforeRequest', cb, { priority: -10 });

      // Remove subscription
      cleanup();
    • Clear all hooks and reset registration state.

      Returns void

      hooks.add('beforeRequest', validator);
      hooks.clear();
      // All hooks removed, back to permissive mode
    • Execute middleware hooks as an onion (nested) composition.

      Unlike run() which executes hooks linearly, pipe() composes hooks as nested middleware. Each hook receives a next function that calls the next layer. The innermost layer is coreFn. Control flow is managed by calling or not calling next() — no ctx.returns() needed.

      Hooks execute in priority order (lower first = outermost layer).

      Type Parameters

      • K extends string | number | symbol
      • R = unknown

      Parameters

      • name: K

        Name of the lifecycle hook

      • coreFn: () => Promise<R>

        The innermost function to wrap

      • ...args: unknown[]

        Arguments passed to each middleware

      Returns Promise<R>

      The result from the middleware chain

      // Retry plugin wraps the fetch call
      hooks.add('execute', async (next, opts, ctx) => {
      for (let i = 0; i < 3; i++) {
      const [result, err] = await attempt(next);
      if (!err) return result;
      await wait(1000 * i);
      }
      throw lastError;
      }, { priority: -20 });

      // Dedupe plugin wraps retry
      hooks.add('execute', async (next, opts, ctx) => {
      const inflight = getInflight(key);
      if (inflight) return inflight;
      const result = await next();
      share(result);
      return result;
      }, { priority: -30 });

      // Execute: dedupe( retry( makeCall() ) )
      const response = await hooks.pipe(
      'execute',
      () => makeCall(opts),
      opts
      );
    • Synchronous version of pipe().

      Type Parameters

      • K extends string | number | symbol
      • R = unknown

      Parameters

      • name: K

        Name of the lifecycle hook

      • coreFn: () => R

        The innermost function to wrap

      • ...args: unknown[]

        Arguments passed to each middleware

      Returns R

      The result from the middleware chain