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

totoms

v2.3.2

Published

Toto Microservice SDK for NodeJS - A fast, cloud-agnostic, opinionated framework for building microservices in the Toto Ecosystem

Readme

Toto Microservice SDK - NodeJS

The Toto Microservice SDK is a framework for building cloud-agnostic microservices. This is the NodeJS SDK documentation.

Table of Contents

  1. Installation
  2. Overview
  3. Usage

Other:

1. Installation

npm install totoms

Cloud-Specific Dependencies

Install the peer dependencies for your target cloud platform:

AWS:

npm install @aws-sdk/client-secrets-manager @aws-sdk/client-sns @aws-sdk/client-sqs

GCP:

npm install @google-cloud/pubsub @google-cloud/secret-manager

2. Overview

Everything starts with TotoMicroservice and the TotoMicroserviceConfiguration. TotoMicroservice is the main orchestrator that coordinates your entire microservice. It initializes and manages:

  • API Controller & API Endpoints: Express-based REST API setup with automatic endpoint registration
  • Message Bus & Message Handlers: Event-driven communication via Pub/Sub and Queues. Registration and routing of event handlers to appropriate topics.
  • Secrets Management: Automatic loading of secrets from your cloud provider
  • Service Lifecycle: Initialization, startup, and shutdown management

The configuration is declarative. The goal is to make it very simple to configure a full microservice, with a syntax that will look like this:

import { getHyperscalerConfiguration, SupportedHyperscalers, TotoMicroservice, TotoMicroserviceConfiguration } from 'totoms';
import { ControllerConfig } from "./Config";
import { SayHello } from './dlg/ExampleDelegate';


const config: TotoMicroserviceConfiguration = {
    serviceName: "toto-ms-ex1",
    basePath: '/ex1',
    environment: {
        hyperscaler: process.env.HYPERSCALER as SupportedHyperscalers || "aws",
        hyperscalerConfiguration: getHyperscalerConfiguration()
    },
    customConfiguration: ControllerConfig,
    apiConfiguration: {
        apiEndpoints: [
            { method: 'GET', path: '/hello', delegate: SayHello }
        ],
        apiOptions: { noCorrelationId: true }
    }, 
};

TotoMicroservice.init(config).then(microservice => {
    microservice.start();
});

A few things you should pay attention to:

  • ControllerConfig - that's your custom configuration class, that you can use to do any type of custom initialization and work (e.g. loading secrets). You can find more details in this section

The TotoMicroserviceConfiguration object specifies:

  • Service Metadata: Service name and base path for API endpoints
  • Environment: Cloud provider (AWS, GCP, Azure) information
  • API Configuration: REST endpoints with their handlers
  • Message Bus Configuration: Topics to subscribe to and message handlers
  • Custom Configuration: Your application-specific settings

3. Usage

3.1. The Toto Microservice Configuration

The microservice is configured through the TotoMicroserviceConfiguration object and the TotoControllerConfig base class. As seen above, you need to define a Custom Configuration Class that extends the TotoControllerConfig base class as shown below here.

import { TotoControllerConfig } from 'totoms';

export class ControllerConfig extends TotoControllerConfig {

    getMongoSecretNames(): { userSecretName: string; pwdSecretName: string; } | null {
        return null;
    }

    getProps(): APIOptions {
        return {}
    }

}

Some things to note:

  • The getMongoSecretNames() method allows you to define the name of the Secrets containing user and pswd of your Mongo DB, if you choose to use it (stored in the Cloud Secrets Manager, depending on the cloud you're deploying to).
  • The getProps() method allows you to do some overrides (e.g. no authentication for this service). You can explore the properties, they're well documented in the SDK.

3.2. Create and Register APIs

Your microservice exposes REST API endpoints using Express. Endpoints are defined when creating the API controller and are automatically set up.

Create a Toto Delegate

Every endpoint needs to be managed by a Toto Delegate. Toto Delegates extend the TotoDelegate abstract class.

This is how you define a Toto Delegate. The following example shows a delegate that processes user creation.

import { TotoDelegate, UserContext, ValidationError, TotoRequest } from 'totoms';
import { Request } from 'express';

class CreateUserDelegate extends TotoDelegate<CreateUserRequest, CreateUserResponse> {

    async do(req: CreateUserRequest, userContext: UserContext): Promise<CreateUserResponse> {

        // Extract data from the request (already validated)
        const { name, email } = req;
        
        // Your business logic here
        ...
        
        // Return the response
        return { 
            id: newUserId,
            name: name,
            email: email
        };
    }
    
    public parseRequest(req: Request): CreateUserRequest {
        // Validate and parse the incoming Express request
        if (!req.body.name) throw new ValidationError(400, "Name is required");
        if (!req.body.email) throw new ValidationError(400, "Email is required");
        
        return {
            name: req.body.name,
            email: req.body.email
        };
    }
}

interface CreateUserRequest extends TotoRequest {
    name: string;
    email: string;
}

interface CreateUserResponse {
    id: string;
    name: string;
    email: string;
}

Register Your Delegate

You can now register your delegate with its endpoint (path, route) in the TotoMicroserviceConfiguration object that we saw earlier.

const config: TotoMicroserviceConfiguration = {
    serviceName: "toto-ms-ex1",
    basePath: '/ex1',
    environment: ...,
    ...
    apiConfiguration: {
        apiEndpoints: [
            { method: 'POST', path: '/users', delegate: CreateUserDelegate }
        ]
    }, 
};

Exposing the OpenAPI Spec through Swagger UI

If you have an OpenAPI Spec defined for your microservice, you can expose it through Swagger UI. To do that, you need to add the following to your TotoMicroserviceConfiguration, in the apiConfiguration section:

    apiConfiguration: {
        ...
        openAPISpecification: { localSpecsFilePath: './openapi.yaml' }
    },

After this the API Documentation will be available at: http(s)://<your-microservice-host>:<port>/<base-path>/apidocs

IMPORTANT - API Documentation is ALSO available as a JSON endpoint at: http(s)://<your-microservice-host>:<port>/<base-path>/jsondocs


3.3. Use a Message Bus

The Message Bus enables event-driven communication between microservices. It supports both PUSH (webhook-based from cloud Pub/Sub) and PULL (polling) delivery models, depending on your cloud provider and configuration.

3.3.1. React to Messages

Message handlers are the primary way to react to events.

Create a Message Handler

Create a handler by extending TotoMessageHandler and implementing the required methods:

import { TotoMessageHandler, TotoMessage, ProcessingResponse } from 'totoms';

class TopicRefreshedEventHandler extends TotoMessageHandler {
    
    getHandledMessageType(): string {
        // Return the message type this handler processes
        return "topicRefreshed";
    }
    
    async processMessage(message: TotoMessage): Promise<ProcessingResponse> {
        // Access message metadata
        const correlationId = message.correlationId;
        const messageId = message.id;
        
        // Extract event data
        const topicName = message.payload.name;
        const blogUrl = message.payload.blogURL;
        const user = message.payload.user;
        
        // Your handler has access to context
        this.logger.compute(correlationId, `Processing topic refresh for: ${topicName}`);
        
        // Perform your business logic
        await this.refreshTopic(topicName, blogUrl, user);
        
        // Return success or failure
        return { success: true };
    }
    
    private async refreshTopic(name: string, url: string, user: string) {
        // Implementation here
    }
}
Register a Message Handler

Register your message handlers with the message bus configuration.

IMPORTANT NOTE:

  • When using PubSub infrastructure, you need to register topics. Topics are registered by giving them:
    • A logical name which is the name that will be used in the application to reference the topic.
    • A topic identifier (e.g., ARN on AWS or fully-qualified Topic Name on GCP)
import { TotoMessageBus, MessageHandlerRegistrationOptions } from 'totoms';

const messageBus = new TotoMessageBus(config, environment);

// Register topics
messageBus.registerTopic({
    logicalName: "topic-events",
    topicName: process.env.TOPIC_EVENTS_TOPIC_NAME! // From environment or secrets
});

// Register message handlers
const handlerOptions: MessageHandlerRegistrationOptions = {
    topic: { logicalName: "topic-events" }
};

messageBus.registerMessageHandler(
    new TopicRefreshedEventHandler(),
    handlerOptions
);

When the microservice starts, it automatically subscribes to the configured topics and routes incoming messages to the appropriate handlers based on their message type.

3.3.2. Publish Messages

You can always publish messages to topics.

NOTE:

  • In the Message Destination, the topic is the logical name of the topic (see above).
import { TotoMessage, MessageDestination } from 'totoms';

async function publishTopicUpdate(messageBus: any, topicId: string, topicName: string) {
    // Create the message
    const message = new TotoMessage({
        type: "topicUpdated",
        correlationId: "correlation-id-123",
        id: topicId,
        payload: { 
            name: topicName, 
            timestamp: new Date().toISOString() 
        }
    });
    
    const destination: MessageDestination = { 
        topicName: "topic-events" 
    };

    await messageBus.publishMessage(destination, message);
}
Getting Access to the Message Bus

There are different ways to get access to the Message Bus instance:

  • Through the TotoMicroservice singleton: TotoMicroservice.getInstance().messageBus

  • Through an existing instance of TotoMicroservice

  • In a TotoMessageHandler you will have messageBus as an instance variable: this.messageBus

  • In a TotoDelegate, you can access it through the config or by maintaining a reference in your application


3.4. Expose MCP Tools

The SDK now supports exposing delegates as Model Context Protocol (MCP) Tools. This allows your microservice to be consumed by AI agents and other MCP-compatible clients.

Creating an MCP-Enabled Delegate

To expose a delegate as an MCP tool, extend TotoMCPDelegate instead of TotoDelegate and implement the getToolDefinition() method:

import { TotoMCPDelegate, UserContext, TotoRequest } from 'totoms';
import { TotoMCPToolDefinition } from 'totoms';
import { Request } from 'express';
import z from 'zod';

export class GetTopics extends TotoMCPDelegate<GetTopicsRequest, GetTopicsResponse> {

    public getToolDefinition(): TotoMCPToolDefinition {
        return {
            name: "getTopics",
            title: "Get user's topics in Tome",
            description: "Retrieves all topics associated with the authenticated user.",
            inputSchema: z.object({}) // Define the input schema using Zod
        }
    }

    async do(req: GetTopicsRequest, userContext: UserContext): Promise<GetTopicsResponse> {
        const user = userContext.email;
        
        // Your business logic here
        const topics = await this.fetchTopicsForUser(user);
        
        return { topics };
    }

    public parseRequest(req: Request): GetTopicsRequest {
        // Parse Express request (for REST API usage)
        return {};
    }
    
    private async fetchTopicsForUser(user: string) {
        // Implementation
        ...
    }
}

interface GetTopicsRequest extends TotoRequest {}

interface GetTopicsResponse {
    topics: any[];
}

Registering MCP Tools

Register your MCP-enabled delegates in the mcpConfiguration section of your microservice configuration:

import { TotoMicroservice, TotoMicroserviceConfiguration } from 'totoms';
import { GetTopics } from './dlg/GetTopics';
import { GetTopic } from './dlg/GetTopic';

const config: TotoMicroserviceConfiguration = {
    serviceName: "tome-ms-topics",
    basePath: '/tometopics',
    environment: ...,
    apiConfiguration: {
        apiEndpoints: [
            { method: 'GET', path: '/topics', delegate: GetTopics }
        ]
    },
    mcpConfiguration: {
        enableMCP: true,
        serverConfiguration: {
            name: "Tome Topics MCP Server",
            tools: [
                GetTopics,
                GetTopic
            ]
        }
    }
};

Key Points

  • Dual Purpose: Delegates extending TotoMCPDelegate can serve both as REST API endpoints AND as MCP tools
  • Tool Definition: The getToolDefinition() method defines how the tool appears to MCP clients
  • Input Schema: Use Zod schemas to define and validate tool inputs
  • Custom Processing: Override processToolRequest() if you need custom logic for MCP tool invocations that differs from REST API handling

3.5. Load Secrets

The SDK handles secret loading from your cloud provider automatically. Access secrets through the configuration or use the SecretsManager directly:

import { SecretsManager } from 'totoms';

const secrets = new SecretsManager({ hyperscaler: "aws" });

// Load a secret by name
const apiKey = await secrets.getSecret("api-key");
const databaseUrl = await secrets.getSecret("database-url");

Secrets are typically stored as environment variable names or secret manager references, depending on your deployment environment.


3.6. Custom Configurations

You can define your own custom configurations by extending the TotoControllerConfig base class.

An example:

import { TotoControllerConfig } from 'totoms';

export class MyServiceConfig extends TotoControllerConfig {
    
    apiKey: string | undefined;
    
    async load(): Promise<void> {
        // Load secrets using the secrets manager
        this.apiKey = await this.secretsManager.getSecret("my-api-key");
    }
    
    getMongoSecretNames() {
        // Return null if your service doesn't use MongoDB
        return null;
    }
}

What you can do with a Custom Configuration:

  1. Load Secrets You can do that by overriding the load() async method and using this.secretsManager.getSecret("your-secret-name") to load secrets.

  2. Configure MongoDB Override getMongoSecretNames(), getDBName(), and getCollections() to configure MongoDB integration.

  3. Custom Authentication Override getCustomAuthVerifier() to provide custom authentication logic.

Core Components

TotoAPIController

The main controller for building REST APIs with Express. Provides:

  • Automatic route registration
  • Built-in validation
  • CORS support
  • Health check endpoints
  • File upload support
  • API documentation generation

TotoMicroservice

High-level wrapper that initializes the entire microservice stack including API controller, message bus, and environment configuration.

TotoMessageBus

Unified interface for pub/sub messaging across cloud platforms:

  • AWS: SNS/SQS
  • GCP: Cloud Pub/Sub
  • Azure: Service Bus (in development)

TotoControllerConfig

Base configuration class for microservices with support for:

  • MongoDB connection management
  • Authentication settings
  • Secrets management
  • Custom validators

Logger

Structured logging with correlation ID support for request tracing.

Validator

Request validation framework with support for:

  • JWT token validation
  • Google OAuth
  • Custom validation logic

Cloud Platform Support

AWS

  • Messaging: SNS (topics), SQS (queues)
  • Secrets: AWS Secrets Manager
  • Region Configuration: Configurable per service

GCP

  • Messaging: Cloud Pub/Sub
  • Secrets: Secret Manager
  • Project Configuration: Uses default project credentials

Azure

  • Messaging: Service Bus (in development)
  • Secrets: Key Vault (in development)

License

MIT

Author

nicolasances

Contributing

Contributions are welcome! Please feel free to submit a Pull Request to the toto-microservice-sdk repository.

Related Projects