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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@remediator/core

v1.6.8

Published

Remix/React Router 7 Mediator

Readme

@remediator/core

A lightweight, CQRS-style mediator for modern JavaScript frameworks.

Focus on your business logic. Decouple your UI from your application layer with a simple, powerful, and type-safe mediator pattern.


Features

  • Type-Safe: Full TypeScript support from end to end.
  • 🚀 Zero Dependencies: A tiny footprint for a fast experience.
  • ⚙️ Optional Vite Plugin: Powerful auto-registration for handlers and middleware.
  • 🛠️ Framework Agnostic: Works with Remix, Next.js, React Router, or any JS project.
  • 📦 Manual & Automatic Modes: Use the Vite plugin for convenience or register handlers manually for ultimate control.

🔧 Install

npm install @remediator/core

🚀 Two Ways to Use reMediator

You can use this package in two modes: Automatic (with the Vite plugin) or Manual.

Mode 1: Auto-Registration with Vite (Recommended)

Let the Vite plugin discover and register your handlers and middleware automatically.

1. Configure the Plugin

Add the plugin to your vite.config.ts.

// vite.config.ts
import { reMediatorPlugin } from "@remediator/core";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    reMediatorPlugin({
      // Options are optional, these are the defaults:
      // path: "app",
      // outputDir: "remediator",
      // includeFileNames: [
      //   "*.mediator.ts",
      //   "*.mediator.server.ts",
      //   "*.server.mediator.ts",
      // ],
    }),
  ],
  // ... other config
});

2. Follow the Naming Conventions

The plugin works by scanning for files and exports that follow specific naming conventions.

  • Files: Must end with .mediator.ts, .mediator.server.ts, or .server.mediator.ts.
  • Handlers: Must be an exported class named XxxHandler.
  • Requests: Must be an exported class named XxxQuery or XxxCommand that matches a handler.
  • Middleware: Must be an exported function named xxxMiddleware.
// app/modules/users/getUser.mediator.ts

// A "Request" class (Query or Command)
export class GetUserQuery implements IRequest<User> {
  // This phantom property is crucial for TypeScript's type inference.
  readonly _response?: User;
  constructor(public id: string) {}
}

// A "Command" that returns nothing
export class DeleteUserCommand implements IRequest<void> {
  readonly _response?: void;
  constructor(public userId: string) {}
}

// A "Handler" class with a matching name
export class GetUserQueryHandler
  implements IRequestHandler<GetUserQuery, User>
{
  async handle(query: GetUserQuery): Promise<User> {
    // Your business logic lives here
    return await getUserFromDb(query.id);
  }
}

// A "Middleware" function
export const authMiddleware: Pipeline = async (req, ctx, next) => {
  if (!ctx.isAuthenticated) throw new Error("Unauthorized");
  return next();
};

3. Import the Generated Client

The plugin generates a remediator/client.ts file. This is the only instance you should import in your application code.

// In your loader, action, or component
import { reMediator } from "~/remediator/client"; // Use your project's path alias

export async function loader({ request, params }: LoaderFunctionArgs) {
  const user = await reMediator.send(GetUserQuery, { id: params.id }, request);
  return json({ user });
}

Mode 2: Manual Registration (For other build tools or full control)

If you aren't using Vite or prefer to be explicit, you can register everything manually.

1. Import from Core

Import the reMediatorInstance and helper functions directly from the core package.

// /app/remediator-setup.ts
import {
  reMediatorInstance,
  registerHandler,
  registerMiddleware,
} from "@remediator/core";

// Import your classes and functions
import {
  GetUserQuery,
  GetUserQueryHandler,
} from "./modules/users/getUser.mediator";
import { authMiddleware } from "./modules/auth/auth.middleware";

// Register everything
registerHandler(GetUserQuery, new GetUserQueryHandler());
registerMiddleware(authMiddleware);

// IMPORTANT: Import this setup file once in your app's entry point (e.g., main.ts)

2. Use the Instance

In the rest of your app, import the default instance from the core package.

import reMediator from "@remediator/core";

export async function loader({ request, params }: LoaderFunctionArgs) {
  const user = await reMediator.send(GetUserQuery, { id: params.id }, request);
  return json({ user });
}

📡 Dispatching Requests

reMediator.send() has two convenient overloads:

  1. Constructor + data: (Recommended) Instantiate and hydrate a request in one step.

    await reMediator.send(
      GetUserQuery, // Request class
      { id: "u123" }, // Properties to hydrate the class
      request, // Raw Request object
      [localMiddleware] // Optional, per-call middleware
    );
  2. Instance: Use a pre-built request object.

    const command = new UpdateOrderCommand("o456", "shipped");
    await reMediator.send(command, request);

🛠️ Middleware

Middleware are powerful functions that run before your handler. They are perfect for cross-cutting concerns like authentication, logging, or caching.

// A middleware function must match the Pipeline signature
export const authMiddleware: Pipeline = async (request, context, next) => {
  // 1. Read from the raw request or context
  const token = context.rawRequest.headers.get("Authorization");

  // 2. Short-circuit the request
  if (!token) throw new UnauthorizedError();

  // 3. Add to the context for downstream handlers
  context.user = await verifyToken(token);

  // 4. Continue to the next middleware or the handler
  return next();
};

🔧 Plugin Options

You can customize the Vite plugin's behavior.

reMediatorPlugin({
  // Directory to search for mediator files.
  path: "app", // Default: 'app'

  // File patterns to include in the scan.
  includeFileNames: [
    // Default:
    "*.mediator.ts",
    "*.mediator.server.ts",
    "*.server.mediator.ts",
  ],

  // Where to write the generated client.ts and manifest.json.
  outputDir: "remediator", // Default: 'remediator'
});

Simple, explicit, and easy to test — perfect for clean frontend architecture.

© 2025 @remediator/core