Skip to Content

registerInstance and registerClassConstructor

@Cat registers methods in the QA catalog (UserService.findById, etc.). For class-style entries (style: 'class'), RPC must also know which object to call those methods on (this).

That is what this page covers: instance registration (your live object) and optional constructor registration (fallback new ClassName()).

Not needed for cat() or catModule() — those invoke the function directly with no class instance.


When do you need registerInstance?

SituationNeed registerInstance?
Class with @Cat methods and empty / safe zero-arg constructorNo — first RPC can new YourClass() automatically
Constructor needs dependencies (db, config, logger, …)Yes — build the service in your app boot and pass it in
You want QA to use the same singleton as production HTTP handlersYes — register that shared instance
Plain functions via cat / catModuleNo

How RPC picks an instance

For fnKey OrdersService.placeOrder, the SDK looks up OrdersService in this order:

  1. registerInstance(yourObject) — if yourObject.constructor.name === 'OrdersService', use it.
  2. Cached singleton — instance created earlier by auto-new in this process.
  3. new OrdersService() — only if a constructor was registered (happens automatically when you use @Cat on a method).
  4. NO_INSTANCE — none of the above worked.

The class name in the fnKey must match instance.constructor.name (the JavaScript class name), not a filename or variable name.


Example A — no registerInstance (demo / simple services)

Constructor has no required parameters. @Cat on methods is enough.

import 'reflect-metadata' import { Cat, Return } from '@gloocan/cat-inspector' class PricingEngine { @Cat computeDiscount(yearsActive: number, monthlySpend: number) { return Return('DISCOUNT', { rate: 0.1 }) } } // Import this file at server startup so decorators run. // First RPC to PricingEngine.computeDiscount → SDK runs new PricingEngine() once.

Same idea as the cat-demo showcase class: no boot-time registerInstance call.


Example B — with dependencies (typical production)

import 'reflect-metadata' import { Cat, Return, Throw, registerInstance } from '@gloocan/cat-inspector' interface OrderRepo { findById(id: string): Promise<{ id: string; total: number } | null> } class OrdersService { constructor(private readonly repo: OrderRepo) {} @Cat async placeOrder(orderId: string, userId: string) { const order = await this.repo.findById(orderId) if (!order) Throw('NOT_FOUND', new Error('order missing')) return Return('PLACED', { orderId, userId, total: order.total }) } } // After you create your real dependencies: const repo: OrderRepo = createOrderRepo(prisma) registerInstance(new OrdersService(repo)) // RPC OrdersService.placeOrder → uses THIS instance (with prisma-backed repo). // SDK will NOT call new OrdersService() with zero args.

Call registerInstance once at application startup (after modules with @Cat are loaded, before accepting QA traffic).


Example C — shared instance for HTTP and QA

Your Express app and QA should share one service object:

const orders = new OrdersService(orderRepo) app.use('/api', ordersRouter) // HTTP uses `orders` via closure or DI container registerInstance(orders) // QA RPC uses the same `orders`

registerInstance(instance: object): void

function registerInstance(instance: object): void

Behavior:

  • Keys the instance by instance.constructor.name (must be non-empty).
  • Duplicate registration for the same class name throws at register time.
  • Passing a non-object is ignored (no-op).

Common mistakes:

MistakeResult
Class renamed but fnKey still uses old nameNO_INSTANCE or wrong class
Anonymous class class { … }Constructor name may be empty → register fails silently
Forgot to import file with @Cat before registerInstanceCatalog empty or instance not wired to entries
Registered instance after first RPC relied on auto-newFirst callers may have used a different singleton; register early

registerClassConstructor (low-level)

function registerClassConstructor( className: string, ctor: new (...args: any[]) => any, ): void

Registers “how to new this class” for step 3 in the resolution order. @Cat on any method already does this for you using the real class constructor.

You rarely call registerClassConstructor directly. Prefer:

  • @Cat on methods — catalog + constructor hook, or
  • registerInstance — your constructed object with deps.

Direct use only when the registered name must differ from normal @Cat behavior (advanced).


Error: NO_INSTANCE

Returned by executeRPC when:

  • No registerInstance for that class name,
  • No cached auto-instance,
  • No constructor registered (no @Cat ran on that class yet),

and the method cannot be invoked.

Fix: Ensure the module defining the class is imported, @Cat is on the method, and either register an instance or use a zero-arg-safe constructor.


Quick comparison

Registration styleCatalog (fnKey)Instance for RPC
cat('Billing.refund', fn)YesNot used (calls fn)
catModule('Billing', { refund() {} })YesNot used
@Cat on class methodsYesregisterInstance or auto new ClassName()

See also