Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@devvir/service-kit

A lightweight toolkit for Node.js microservices. Handles the scaffolding — health checks, graceful shutdown, provider connections, HTTP and WebSocket servers and clients, and structured logging — so your service focuses on its tasks.

Install

pnpm install @devvir/service-kit

Usage

The minimal case:

import SK from '@devvir/service-kit';

SK.run(async (service) => {
  service.logger.info('Running!');
});

Out of the box you get a health check on port 3000 and graceful shutdown on SIGTERM/SIGINT. Shutdown listeners can be async — all are awaited before the process exits. No configuration required.


Declare config, bind lifecycle hooks, then run:

import SK from '@devvir/service-kit';

SK.declare({
  name:   'api',
  config: { port: parseInt(process.env.PORT || '3001') },
});

SK.bind({
  onShutdown: async (service) => {
    await cleanup();
    service.logger.info('cleaned up');
  },
});

SK.run(async (service) => {
  const port = service.config('port') as number;
  startServer(port);
});

Connect to a database or queue in your service function:

import SK, { type Service } from '@devvir/service-kit';

SK.declare({
  name: 'worker',
  providers: {
    rabbitmq: { url: process.env.AMQP_URL },
  },
});

SK.run(async (service: Service) => {
  const conn = await service.providers.connect('rabbitmq');
  // start consuming...
});

Declare HTTP/WebSocket servers and outbound clients. The kit owns the boilerplate — routing, the error handler, retries, reconnection, and clean transition logs:

import SK, { type ExpressServerHandle, type FetchClientHandle } from '@devvir/service-kit';

SK.declare({
  name:    'api',
  servers: { type: 'express' },
  clients: { name: 'upstream', type: 'fetch', url: process.env.UPSTREAM_URL },
});

SK.run(async (service) => {
  const upstream = service.clients.get('upstream') as FetchClientHandle;
  const api      = service.servers.get() as ExpressServerHandle;

  api.addRoute('get', '/status', async (_req, res) => {
    res.json(await upstream.get('/health'));
  });

  await api.start();
});

A fetch client retries transient failures with capped backoff and logs an outage once, not once per attempt; a ws client reconnects with single-flight backoff. Both go from declaration to working handle with no hand-rolled loop.


Access any running service — or just its config, state, or providers — from anywhere in the process without prop drilling:

import { registry, SK_CONFIG, SK_STATE, SK_PROVIDERS } from '@devvir/service-kit';

// From a module that has no reference to the service object:
const svc       = registry.get('worker');
const config    = registry.get('worker', SK_CONFIG);    // → service.config()
const state     = registry.get('worker', SK_STATE);     // → service.state()
const providers = registry.get('worker', SK_PROVIDERS); // → service.providers

SK.run() registers the service automatically when the spec includes a name. Registration fails fast if two services with the same name are started in one process — early detection for misconfiguration.

// In tests — swap out the real service with a controlled mock:
import { registry } from '@devvir/service-kit';
beforeEach(() => registry.clear());

Documentation

Full documentation →

About

A comprehensive lifecycle and infrastructure management library for Node.js microservices

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages