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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@yamf/core

v0.3.2

Published

A lightweight, zero-dependency microservices framework for Node.js with built-in service discovery, api gateway, pub/sub messaging, HTTP routing, and load balancing.

Readme

@yamf/core

A lightweight, zero-dependency microservices framework for Node.js with built-in service discovery, pub/sub messaging, HTTP routing, and load balancing.

Tests Node License

Features

Zero Dependencies - Pure Node.js implementation
🔍 Service Discovery - Automatic service registration and lookup
📡 Pub/Sub Messaging - Built-in publish-subscribe pattern
🔄 Load Balancing - Round-robin and random distribution strategies
🛣️ HTTP Routing - Direct and wildcard route support
💾 Built-in Services - Cache, auth, static files, and file upload services
🌍 Multi-Language Support - Python client available, Go coming soon
🧪 Fully Tested - Comprehensive tests with 85%+ coverage
📦 Modular Architecture - Clean, maintainable codebase

Installation

npm install @yamf/core

Quick Start

export YAMF_REGISTRY_URL=http://localhost:9999

Basic Service Example

import { registryServer, createService, callService } from '@yamf/core'

// Start the registry
await registryServer()

// Create a service
await createService(function helloService(payload) {
  return { message: 'Hello, ' + payload.name }
})

// Call the service
const result = await callService('helloService', { name: 'World' })
console.log(result.message) // "Hello, World"

Core Concepts

Service Registry

The registry server is the heart of @yamf/core. It automatically:

  • Tracks all service instances and their locations
  • Handles service registration and unregistration
  • Provides service discovery and load balancing
  • Routes HTTP requests to services
  • Manages pub/sub subscriptions
import { registryServer } from '@yamf/core'

// Start the registry (typically once per application/cluster)
const registry = await registryServer()

// The registry automatically assigns ports starting from REGISTRY_PORT + 1
// Clean shutdown
await registry.terminate()

Plain Old Services

Services are just functions that receive a payload and return a result:

import { createService } from '@yamf/core'

// Simple service
await createService(function calculateService(payload) {
  return { result: payload.a + payload.b }
})

// Service that calls other services
await createService(function orchestratorService(payload) {
  const result1 = await this.call('serviceA', payload)
  const result2 = await this.call('serviceB', result1)
  return result2
})

Service Lifecycle:

  1. Service registers with the registry
  2. Registry assigns a port and location
  3. Service subscribes to registry updates
  4. Service is available for calls
  5. On termination, service unregisters gracefully

Pub/Sub Services

Event-driven services:

import { createSubscriptionService, publishMessage } from '@yamf/core'

const subService = await createSubscriptionService('subService', 'orders', async (message) => {
  console.log('New order:', message)
})

// does a lookup/publish through the service registry
await publishMessage('orders', {
  orderId: 'order-1',
  price: '19.99'
})

const publishingService = await createService('publishingService', async (payload) => {
  // do some stuff
  // then publish from this service context (calls subscribers directly)
  await this.publish('orders', {
    orderId: 'order-2',
    price: '21.99'
  })
})

Subscription Service Lifecycle:

  1. Service registers with the registry
  2. Registry assigns a port and location
  3. Service subscribes to registry updates and additional subscription channel(s)
  4. Service is available for publish events
  5. On termination, service unregisters and cleans up subscriptions gracefully

HTTP Routes

Create HTTP endpoints that map to services:

import { createRoute } from '@yamf/core'

// Route with inline service
await createRoute('/api/users', function usersService(payload) {
  return { users: ['Alice', 'Bob'] }
})

// Route pointing to existing service
await createRoute('/api/greet', 'greetingService')

// Wildcard routes (controller pattern)
await createRoute('/api/users/*', function usersController(payload) {
  const { url } = payload
  // Handle /api/users/123, /api/users/profile, etc.
  return { path: url }
})

// Now visit: http://localhost:9999/api/users

Built-in Services (separate modules)

Cache Service

In-memory caching with automatic eviction:

import { createCacheService } from '@yamf/services-cache'

const cache = await createCacheService({
  expireTime: 60000,      // Default TTL: 60 seconds
  evictionInterval: 30000  // Check every 30 seconds
})

// Use via callService
await callService('cache', { set: { userId123: { name: 'Alice' } } })
await callService('cache', { get: 'userId123' })
await callService('cache', { del: { userId123: true } })
await callService('cache', { clear: true })

Static File Service

Serve static files with flexible routing:

import { createStaticFileService } from '@yamf/services-file-server'

const staticServer = await createStaticFileService({
  rootDir: './public',
  urlRoot: '/assets',
  fileMap: {
    '/': 'index.html',
    '/styles/*': 'css',
    '/assets/*': 'public/assets'
  }
})

File Upload Service

Note: Unlike @yamf/core, this service uses busboy as a runtime dependency.

Handle multipart file uploads with validation:

import { createFileUploadService } from '@yamf/services-file-upload'

const uploadService = await createFileUploadService({
  uploadDir: './uploads',
  fileFieldName: 'file',
  textFields: ['title', 'description'],
  validateFile: (filename, mimetype) => {
    return mimetype.startsWith('image/')
  }
})

Multi-Language Support

@yamf/core supports multiple programming languages, allowing you to build polyglot microservice architectures. All clients communicate with the same registry using a standard HTTP protocol.

Python Client

Full-featured Python client with support for all core features:

from yamf import create_service_sync, call_service_sync
import os

os.environ['YAMF_REGISTRY_URL'] = 'http://localhost:3000'

# Create a Python service
def my_service(payload):
    return {"message": f"Hello from Python: {payload.get('name')}!"}

service = create_service_sync("my_service", my_service)

# Call other services (Node.js or Python)
result = call_service_sync("other_service", {"data": "test"})

Features:

  • ✅ Service creation and registration
  • ✅ Service-to-service calls
  • ✅ HTTP routes
  • ✅ Pub/sub messaging
  • ✅ Async/sync APIs

Documentation: See src/api/languages/python/README.md
Examples: See examples/python-services/

Go Client (Coming Soon)

Go client library is currently in development.

Documentation: See src/api/languages/go/README.md

Creating Services in Multiple Languages

Services can seamlessly communicate regardless of implementation language:

// Node.js service
await createService(function nodeService(payload) {
  // Call Python service
  return await this.call('pythonService', payload)
})
# Python service
async def python_service(self, payload):
    # Call Node.js service
    result = await self.call('nodeService', payload)
    return result

Load Balancing

Automatic load balancing when multiple instances of the same service exist:

// Create multiple instances of the same service
await createService(function workerService(payload) {
  return { instance: 'A', result: payload.value * 2 }
})

await createService(function workerService(payload) {
  return { instance: 'B', result: payload.value * 2 }
})

// Calls are automatically distributed using round-robin
const result1 = await callService('workerService', { value: 1 }) // → instance A
const result2 = await callService('workerService', { value: 2 }) // → instance B

Strategies: Round-robin for callService(), random for service lookup.

Error Handling

Services can throw HTTP errors with status codes:

import { HttpError } from '@yamf/core'

await createService(function validateService(payload) {
  if (!payload.userId) {
    throw new HttpError(400, 'Missing required field: userId')
  }
  return { status: 'authorized' }
})

// Errors are automatically propagated with proper HTTP status codes
try {
  await callService('validateService', {})
} catch (err) {
  console.log(err.status)  // 400
  console.log(err.message) // "Missing required field: userId"
}

Environment Variables

# Required - Registry server URL
export YAMF_REGISTRY_URL=http://localhost:8080

# Optional - Service-specific URL (for containerized deployments)
export YAMF_SERVICE_URL=http://myservice:10000

API Reference

Core Functions

registryServer(port?: number): Promise<Server>

Start the registry server. Port defaults to value from YAMF_REGISTRY_URL.

createService(name: string | Function, serviceFn?: Function, options?: Object): Promise<Server>

Create and register a service. Accepts named functions or separate name/function parameters.

callService(name: string, payload: any): Promise<any>

Call a service by name with automatic load balancing.

createRoute(path: string, service: string | Function, dataType?: string): Promise<Server>

Register an HTTP route. Supports wildcards (/api/users/*).

publishMessage(channel: string, message: any): Promise<any>

Publish a message to a pub/sub channel.

HttpError(status: number, message: string)

Create HTTP errors with status codes for service responses.

Service Helper Functions

createCacheService(options?: CacheOptions): Promise<Server>

Create an in-memory cache service with TTL and eviction.

Options:

  • expireTime?: number - Default TTL in ms (default: 600000)
  • evictionInterval?: number - Eviction check interval in ms (default: 30000)

Cache Commands (via callService):

  • { get: key } - Get a value
  • { set: { key: value } } - Set a value
  • { del: { key: true } } - Delete a value
  • { clear: true } - Clear all values

createPubSubService(): Promise<PubSub>

Create a pub/sub service for event-driven messaging.

Methods:

  • publish(channel, message) - Publish to channel
  • subscribe(channel, handler) - Subscribe with callback
  • unsubscribe(channel, subId) - Remove subscription
  • terminate() - Clean shutdown

createStaticFileService(options?: StaticOptions): Promise<Server>

Serve static files with flexible routing and security.

Options:

  • rootDir?: string - Base directory (default: cwd)
  • urlRoot?: string - URL prefix (default: '/')
  • fileMap?: Object - URL to file mappings
  • simpleSecurity?: boolean - Basic path traversal protection

createFileUploadService(options?: UploadOptions): Promise<Server>

Handle multipart file uploads with validation. Requires busboy dependency.

Options:

  • uploadDir?: string - Upload directory (default: './uploads')
  • fileFieldName?: string - Form field name (default: 'file')
  • textFields?: string[] - Additional form fields to capture
  • validateFile?: Function - File validation callback

Roadmap

v1.0 (MVP)

  • [x] Service registry and discovery
  • [x] HTTP routing
  • [x] Pub/sub messaging
  • [x] Cache service
  • [x] Load balancing
  • [x] Comprehensive tests
  • [x] Modular architecture
  • [x] Python client library
  • [ ] Go client library
  • [ ] Read-only (cache-control) support
  • [ ] CLI tools
  • [ ] Multi-container integration tests
  • [ ] Cluster failover paradigms
  • [ ] Production mode (no error traces)
  • [ ] Basic access control

Future

  • [ ] Service mesh capabilities
  • [ ] Distributed tracing
  • [ ] Metrics and monitoring
  • [ ] Rate limiting
  • [ ] Circuit breakers
  • [ ] API gateway features
  • [ ] Additional language clients (Ruby, C#, Java, Rust)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT

Credits

Built with ❤️ using pure Node.js - no external dependencies required.