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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@treatwell/moleculer-call-wrapper

v1.0.2

Published

[![](https://cdn1.treatwell.net/images/view/v2.i1756348.w200.h50.x4965194E.jpeg)](https://treatwell.com/tech)

Downloads

16

Readme

moleculer-call-wrapper

npm

This plugin intends to generate a TS file exporting a call function to replace ctx.call in your moleculer project when using the @treatwell/moleculer-essentials package.

Purpose

In moleculer, when you want to call an action from another service, you use ctx.call('service.action', params). With TypeScript, you don't have any type safety on the action name or the params you pass to it.

By using @treatwell/moleculer-essentials, you can safely define your actions with types, but you still don't have type safety when calling them.

This package solves this by generating a call function with the correct types for each action in your project. Here is an example of how it looks like:

// test.service.ts
import type { Context } from 'moleculer';
import { wrapService } from '@treatwell/moleculer-essentials';

export default wrapService({
  name: 'test',
  actions: {
    simpleaction: {
      async handler(ctx: Context<void>): Promise<void> {
        // ...
      },
    },
    withparams: {
      async handler(ctx: Context<{ id: number }>): Promise<void> {},
    },

    withresponse: {
      async handler(ctx: Context<void>): Promise<{ name: string }> {
        return { name: 'test' };
      },
    },

    withboth: {
      async handler(ctx: Context<{ id: number }>): Promise<{ name: string }> {
        return { name: 'test' };
      },
    },

    withtemplate: {
      async handler<T extends 'test' | 'other'>(
        ctx: Context<{ id: number; type: T }>,
      ): Promise<{ name: T }> {
        return { name: 'test' as T };
      },
    },
  },
});
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unused-vars */
import type * as m from 'moleculer';

interface Actions {
  'test.withparams': [{ id: number }, unknown];
  'test.withboth': [{ id: number }, { name: string }];
}
interface ActionsU {
  'test.simpleaction': void;
  'test.withresponse': { name: string };
}

export function call<N extends keyof Actions>(
  ctx: m.Context,
  action: N,
  params: Actions[N][0],
  meta?: m.CallingOptions,
): Promise<Actions[N][1]>;
export function call<N extends keyof ActionsU>(
  ctx: m.Context,
  action: N,
  params?: undefined,
  meta?: m.CallingOptions,
): Promise<ActionsU[N]>;
export function call(
  ctx: m.Context,
  action: string,
  params: unknown,
  meta?: m.CallingOptions,
): Promise<unknown> {
  return ctx.call(action, params, meta);
}

export function callT<
  T extends 'test' | 'other',
  N extends string = 'test.withtemplate',
>(
  ctx: m.Context,
  action: N,
  params: N extends 'test.withtemplate' ? { id: number; type: T } : never,
  meta?: m.CallingOptions,
): Promise<{ name: T }>;
export function callT(
  ctx: m.Context,
  action: string,
  params: unknown,
  meta?: m.CallingOptions,
): Promise<unknown> {
  return ctx.call(action, params, meta);
}

Then you can just use it like this:

import { call, callT } from './call';
// ...

const res = await call(ctx, 'test.withresponse');

const tRes = await callT(ctx, 'test.withtemplate', {
  id: 1,
  type: 'test',
});

Installation

Install moleculer-call-wrapper with your package manager:

  yarn add -D @treatwell/moleculer-call-wrapper

This package has a peerDependency to typescript >= 5.8. You need to have it declared in your dev dependencies.

Usage

To generate the wrapper file, you need to call the createWrapperCall function exported by the package and provide:

  • wrapperPath: the path where you want to generate the file (e.g. src/call.ts)
  • services: An array of moleculer services (result from broker.loadService(file) for example)
  • svcFiles: An array of those services file paths (MUST be in the same order as services)
  • additionalBuiltins: An array of functions allowing you to add additional actions manually (see below)

Example:

import * as path from 'path';
import * as fs from 'fs';
import fg from 'fast-glob';
import {
  createServiceBroker,
  HealthCheckMiddleware,
  createLoggerConfig,
  defaultLogger,
  getMetadataFromService,
  isServiceSelected,
  Selector,
} from '@treatwell/moleculer-essentials';

async function run() {
  // In your case, you would probably use glob or similar to find your service files
  const serviceFiles = ['src/services/test.service.ts'];

  const broker = createServiceBroker({});
  const services = serviceFiles.map(f => broker.loadService(f));

  // This should be done on dev mode only, not in production
  if (process.env.MOLECULER_CALL_WRAPPER === 'yes') {
    import('@treatwell/moleculer-call-wrapper')
      .then(async ({ createWrapperCall }) => {
        return createWrapperCall(
          './lib/call.ts',
          services,
          serviceFiles,
          additionalBuiltins,
        );
      })
      .catch(err => {
        broker.logger.error('Error while creating call wrapper', err);
      });
  }

  await broker.start();
}

run().catch(err => {
  defaultLogger.error('Error while starting server', { err });
  process.exit(1);
});

Builtins

Mixins can't be understood by the plugin natively. As a workaround, it will try to match known mixins and generate related types for them.

It only concerns mixins that generates actions.

Mixins (namely the DatabaseMixin) present in the @treatwell/moleculer-essentials package are automatically included.

Create your own builtins

To create your own builtins, you can take a look at this file.

The idea is to first check if the service is using the related mixin. If it is, the builtin will have to:

  • Fill the related action (in the actions array) with TS types.
  • Add any imports used in those TS types with the addDepToImports function to the context.imports map.

To help you with TS factory and AST, you can use https://ts-ast-viewer.com/

License

MIT