rpc package

Type-safe RPC over a message queue — services, clients and the decorators that describe them, built on @imqueue/core.

Write a service by extending IMQService and marking each remotely callable method with @expose(). Complex argument and return types need a class-level @classType() (or @indexed()) plus @property() on each field. Then generate a typed client for that service with IMQClient.create(), which reads the running service's own description.

Remarks

Decorator protocol. This package targets standard (TC39) decorators. Consuming projects must compile with experimentalDecorators: false, removeComments: false, and esnext.decorators in lib. The decorators still work under legacy compilation, but behaviour differs — see classType, which is required under standard decorators and a no-op under legacy, and expose, whose registration is deferred to first construction under standard decorators.

removeComments: false is not optional: standard decorators provide no runtime type reflection, so an exposed method's JSDoc is the only source of argument and return types for the generated client, and the documented @param list is what the service's argument-count check validates.

Importing this package installs a global Symbol.metadata polyfill, which standard decorator metadata depends on.

Re-exports. This package re-exports the entire @imqueue/core surface, so core types and helpers can be imported from either package. The one exception is core's default-exported IMQ factory: export * never forwards a default, so import IMQ from '@imqueue/rpc' yields undefined — import it from @imqueue/core directly.

Example

import { IMQService, IMQClient, expose } from '@imqueue/rpc';

class UserService extends IMQService {
    // NOTE: a real service needs a JSDoc block here with typed
    // @param / @returns tags — that is where the generated client
    // gets its types from
    @expose()
    public async count(active: boolean): Promise<number> {
        return 42;
    }
}

await new UserService().start();

// elsewhere — generates and loads a typed client
const ns = await IMQClient.create('UserService');
const client = new ns.UserClient();

await client.start();
console.log(await client.count(true));

Classes

Class

Description

Description

The self-description a service serves to its clients, and the input to client generation.

IMQCache

Process-wide static registry of cache adapters.

IMQDelay

Represents a delay expressed as a numeric timer value in a given time unit. Used to defer IMQ request processing.

IMQLock

In-process, promise-based locks used to collapse concurrent identical calls: the first caller executes the work while later callers for the same key wait and are then resolved with the first caller's result.

IMQMetadata

Arbitrary, JSON-serializable metadata bag carried alongside an IMQ request. Each property value must be a valid JSON value.

IMQRPCDescription

Process-global registry of RPC metadata gathered by the decorators.

RedisCache

Class RedisCache. Implements a cache engine on top of Redis.

Abstract Classes

Abstract Class

Description

IMQClient

Base class for service clients.

Subclass it and declare every remote method as @remote() async m(...args) \{ return await this.remoteCall<T>(...arguments); \}, or let IMQClient.create() generate the subclass from a running service's description.

IMQService

Class IMQService Basic abstract service (server-side) implementation

Functions

Function

Description

classType()

Registers a complex-type class's @property field definitions into the RPC type description, so the type can be exposed to service clients.

currentMetadata()

Returns the metadata of the in-flight IMQ request for the current async execution, if any. Returns undefined outside of a runWithRequest() scope. The transport carries metadata as an opaque bag; callers interpret its fields.

expose()

Makes a service method callable remotely by registering it in the RPC service description.

imqCallRejector(reject, req, client)

Builds a call rejector that rejects the pending promise and then runs the optional after-call hook.

imqCallResolver(resolve, req, client)

Builds a call resolver that resolves the pending promise and then runs the optional after-call hook.

IMQError(code, message, stack, method, args, original)

Builds a JSON representation of an IMQ error.

indexed(indexTypedef)

Exposes a complex service type that carries an index signature.

lock(enabledOrOptions)

Creates a @lock() method decorator. Concurrent calls to the decorated method that share the same arguments are coalesced: only the first call is executed, and all the others resolve with its result. Call similarity is determined by the method's argument values. The returned decorator is dual-mode: it works both as a standard (TC39) and as a legacy method decorator.

logged(options)

Creates a @logged() method decorator that wraps the decorated method in a try/catch and logs any error it throws. The logger is resolved in this order: an explicitly passed logger, then a logger defined on the instance or on the class, and finally the global console. By default the error is re-thrown after being logged; pass { doNotThrow: true } to swallow it. The returned decorator is dual-mode: it works both as a standard (TC39) and as a legacy method decorator.

parseSourceComments(src, className)

Extracts method JSDoc blocks from original source text of a given class.

The text may be TypeScript (type annotations, generics, modifiers, decorators), which acorn cannot parse — so extraction is textual: the search is narrowed to the class region (from the class declaration to the next class declaration or EOF), and each doc block is attributed to the method whose declaration head immediately follows it. When several blocks precede a method, the closest one wins, matching the runtime parser.

property(type, isOptional)

Marks a class field as part of an exposed complex type, so it is described to clients and appears in the generated client interfaces.

registerType(ctor, metadata, indexType)

Flushes @property definitions collected on a class into the RPC type description. Invoked by class-level decorators once the class (and hence its name) is available.

remote()

Creates a @remote() method decorator for client classes. The decorated method has the remote method name appended to its arguments and is then forwarded to remoteCall(). The returned decorator is dual-mode: it works both as a standard (TC39) and as a legacy (experimentalDecorators) method decorator.

runWithRequest(request, fn)

Runs the given function with request bound to the current async execution context, so any code reached from it (and its asynchronous continuations) can access the in-flight request's metadata via currentMetadata() without threading it through call signatures.

The binding is scoped to the function: it is established for the duration of the call and automatically removed afterwards, which keeps concurrent requests isolated from one another.

send(request, response, service)

Sends IMQ response with support of after call optional hook

Interfaces

Interface

Description

ArgDescription

Description of one argument of an exposed method, as parsed from its JSDoc.

CacheDecorator

The type of the cache export: a decorator factory that also carries process-wide defaults.

CacheDecoratorOptions

Per-method options for the cache decorator.

ICache

Generic cache adapter interface. Any cache engine implementation must conform to this contract to be usable within IMQ.

ICacheConstructor

Constructor signature the registry uses to instantiate a cache adapter class.

IMQAfterCall

Hook invoked after a call has been handled.

IMQBeforeCall

Hook invoked before a call is dispatched.

IMQClientOptions

Options accepted by a generated IMQ client.

IMQLockMetadata

Map from lock key to the metadata describing the call currently associated with that key.

IMQLockMetadataItem

Diagnostic description of a locked call.

IMQMetricsServerOptions

Options for the built-in metrics server.

IMQRPCError

Failure descriptor for a remote call.

Produced by a service when a method throws, and also before dispatch when the method does not exist, is not exposed, or was called with the wrong number of arguments. A client additionally synthesizes one locally on call timeout.

IMQRPCRequest

Wire format of a remote call, produced by a client and consumed by a service.

IMQRPCResponse

Response message data structure that a service replies with to handled requests.

IMQServiceOptions

Options accepted by an IMQ service.

IMQWrapCall

Around hook wrapping the actual service method invocation. It receives the request/response and a next callback that runs the method and resolves to its return value; it MUST call next() (returning its resolved value) to produce the response data. Unlike beforeCall/afterCall, this lets a hook run the method inside its own scope — e.g. establishing an OpenTelemetry context so any spans the method (and its downstream calls) create nest under the request span. When unset, the method is invoked directly.

IRedisCacheOptions

Options accepted by RedisCache.init().

LockOptions

Options for the lock() decorator.

LoggedDecoratorOptions

Options for the logged() decorator.

MethodDescription

Description of one exposed method: its summary, its positional arguments and its return value.

MethodsCollectionDescription

Map of method name to method description.

PropertyDescription

Description of one property of an exposed complex type.

ReturnValueDescription

Description of an exposed method's return value, as parsed from its JSDoc.

ServiceClassDescription

The exposed methods a single class declares, plus its parent's name.

ServiceDescription

Raw registry of every class that declares exposed methods, keyed by class name — the storage format behind IMQRPCDescription.serviceDescription.

Thunk

A zero-argument function whose return value is resolved lazily.

Used by property() and indexed() so a type definition can reference a class that is not yet initialized at decoration time — self-references and forward references.

TypeDescription

The property bag of a single exposed type: property name to property description.

TypesDescription

Every exposed complex type, keyed by class name.

Variables

Variable

Description

AFTER_HOOK_ERROR

Prefix used when logging a failure inside an afterCall hook.

BEFORE_HOOK_ERROR

Prefix used when logging a failure inside a beforeCall hook.

cache

Creates a @cache() method decorator that memoizes the decorated method's result in a cache adapter (RedisCache by default). On each call the cache is checked first; on a miss the method runs, and its result is stored under a key derived from the class name, method name, and arguments. The returned decorator is dual-mode: it works both as a standard (TC39) and as a legacy method decorator.

DEFAULT_IMQ_CLIENT_OPTIONS

Default options applied to every generated IMQ client: the core queue defaults, plus cleanup enabled with a '*:client' filter and the code-generation settings.

DEFAULT_IMQ_METRICS_SERVER_OPTIONS

Default metrics server options

DEFAULT_IMQ_SERVICE_OPTIONS

Default options applied to every IMQ service: the core queue defaults, plus cleanup enabled with a '*:client' filter, single-process mode, and one worker per core.

DEFAULT_REDIS_CACHE_OPTIONS

Default options for RedisCache: the standard queue defaults, with prefix overridden to imq-cache so cache keys never collide with queue keys under the imq prefix.

REDIS_CLIENT_INIT_ERROR

Message of the TypeError thrown by any RedisCache operation invoked before a connection has been established. Exported so callers can match on it.

Type Aliases

Type Alias

Description

AcquiredLock

What IMQLock.acquire() resolves to: the literal true when this caller acquired the lock and must perform the work, or the value the lock holder passed to IMQLock.release() when this caller had to wait.

ICacheAdapter

Accepted cache adapter references: a constructor, an instance, or an adapter name.

IMQLockQueue

The FIFO queue of callers waiting on a single lock key, drained in arrival order when the lock is released.

IMQLockTask

Internal representation of one queued waiter: its promise's [resolve, reject] pair, selected by IMQLock.release() according to whether an error was supplied.

LoggedLogLevel

Names of the ILogger methods logged() can use to record a caught error.

Read this page as plain markdown — no HTML, no navigation. For pasting into an LLM, or for an agent to fetch.