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

ods-utils

v1.13.0

Published

Shared utilities for microservices architecture

Readme

ODS Utils

A comprehensive collection of shared utilities. This package provides standardized solutions for common tasks in Node.js microservices, helping teams maintain consistency and reduce code duplication.

Table of Contents

Features

  • Configuration Management: Centralized configuration with environment variable support
  • Structured Logging: Consistent logging format across services
  • Caching: Multiple caching providers (Redis, in-memory) with support for custom providers
  • Database Connectivity: MongoDB and PostgreSQL connection management and utilities
  • Response Handling: Framework-agnostic standardized API responses (Express, Koa, Fastify, Hapi, and custom adapters)
  • Authentication: JWT-based authentication middleware for Express
  • Rate Limiting: Configurable rate limiting for API protection
  • Date Utilities: Comprehensive date manipulation, formatting, parsing, and comparison utilities

Installation

npm install ods-utils

Usage

Configuration

Load and access configuration values from environment variables:

const { config } = require("ods-utils");

// Load configuration
const appConfig = config.load();
console.log(appConfig.port); // Access configuration values

Logging

Structured logging with different log levels:

const { logger } = require("ods-utils");

logger.info("This is an info message");
logger.error("This is an error message", { userId: "123", errorCode: "AUTH_FAILED" });
logger.debug("Debug information", { requestId: "req-123" });

Caching

The caching module supports multiple providers (Redis, in-memory) and allows you to create custom providers.

Redis Provider (Default)

const { cache } = require("ods-utils");

// Initialize Redis cache with project-specific configuration
cache.init({
  redis: {
    url: process.env.REDIS_URL || "redis://localhost:6379",
    username: process.env.REDIS_USERNAME,
    password: process.env.REDIS_PASSWORD,
    pool: {
      min: parseInt(process.env.REDIS_POOL_MIN) || 1,
      max: parseInt(process.env.REDIS_POOL_MAX) || 10,
    }
  }
});

// Set a value in the cache
await cache.set("key", { value: "data" }, 3600); // TTL in seconds

// Get a value from the cache
const value = await cache.get("key");

// Delete a value from the cache
await cache.del("key");

// Clear the entire cache
await cache.clear();

In-Memory Provider

const { cache } = require("ods-utils");
const { MemoryProvider } = cache.providers;

// Initialize with in-memory provider
cache.init({
  provider: new MemoryProvider(),
  memory: {
    maxSize: 100, // Maximum number of items to store
    cleanupInterval: 30000 // Cleanup interval in milliseconds (30 seconds)
  }
});

// Use the cache with the same API as Redis provider
await cache.set("key", { value: "data" }, 3600);
const value = await cache.get("key");
await cache.del("key");
await cache.clear();

Custom Provider

You can create your own cache provider by extending the CacheProvider base class:

const { cache } = require("ods-utils");
const { CacheProvider } = cache.providers;

// Create a custom provider
class MyCustomProvider extends CacheProvider {
  constructor() {
    super();
    this.data = {}; // Your storage mechanism
  }

  init(options) {
    // Initialize your provider with options
    console.log("Custom provider initialized with options:", options.custom || {});
  }

  async set(key, value, ttl) {
    // Implement set logic
    this.data[key] = value;
    return true;
  }

  async get(key) {
    // Implement get logic
    return this.data[key] || null;
  }

  async del(key) {
    // Implement delete logic
    delete this.data[key];
    return true;
  }

  async clear() {
    // Implement clear logic
    this.data = {};
    return true;
  }
}

// Initialize with your custom provider
cache.init({
  provider: new MyCustomProvider(),
  custom: {
    // Your custom options
    someSetting: "value"
  }
});

// Use the cache with the same API
await cache.set("key", { value: "data" });
const value = await cache.get("key");

Database

Database connection management and utilities for MongoDB and PostgreSQL:

MongoDB

const { db } = require("ods-utils");

// Initialize MongoDB connection
await db.mongodb.init({
  mongodb: {
    uri: process.env.MONGODB_URI || "mongodb://localhost:27017",
    dbName: process.env.MONGODB_DB_NAME || "myapp",
    options: {
      maxPoolSize: 10,
      minPoolSize: 1,
      connectTimeoutMS: 5000,
    }
  }
});

// Find documents in a collection
const users = await db.mongodb.find("users", { active: true });

// Find a single document
const user = await db.mongodb.findOne("users", { email: "[email protected]" });

// Insert a document
const result = await db.mongodb.insertOne("users", {
  name: "John Doe",
  email: "[email protected]",
  createdAt: new Date()
});

// Update a document
await db.mongodb.updateOne(
  "users",
  { email: "[email protected]" },
  { $set: { lastLogin: new Date() } }
);

// Delete a document
await db.mongodb.deleteOne("users", { email: "[email protected]" });

// Perform an aggregation
const stats = await db.mongodb.aggregate("users", [
  { $match: { active: true } },
  { $group: { _id: "$role", count: { $sum: 1 } } }
]);

// Close the connection when your application shuts down
await db.mongodb.close();

PostgreSQL

const { db } = require("ods-utils");

// Initialize PostgreSQL connection pool
db.postgresql.init({
  postgresql: {
    connectionString: process.env.DATABASE_URL,
    // Or provide individual connection parameters
    host: process.env.DB_HOST || "localhost",
    port: process.env.DB_PORT || 5432,
    database: process.env.DB_NAME || "myapp",
    user: process.env.DB_USER || "postgres",
    password: process.env.DB_PASSWORD,
    max: 10, // Maximum number of clients in the pool
    idleTimeoutMillis: 30000,
  }
});

// Execute a simple query
const result = await db.postgresql.query(
  "SELECT * FROM users WHERE active = $1",
  [true]
);
console.log(result.rows);

// Find rows in a table
const users = await db.postgresql.find("users", { active: true });

// Find a single row
const user = await db.postgresql.findOne("users", { email: "[email protected]" });

// Insert a row
const newUser = await db.postgresql.insert("users", {
  name: "Jane Doe",
  email: "[email protected]",
  created_at: new Date()
});

// Update rows
const updatedUsers = await db.postgresql.update(
  "users",
  { email: "[email protected]" },
  { last_login: new Date() }
);

// Delete rows
const deletedUsers = await db.postgresql.remove("users", { email: "[email protected]" });

// Execute a transaction
await db.postgresql.transaction(async (client) => {
  await client.query("UPDATE accounts SET balance = balance - $1 WHERE user_id = $2", [100, 1]);
  await client.query("UPDATE accounts SET balance = balance + $1 WHERE user_id = $2", [100, 2]);
});

// Close the connection pool when your application shuts down
await db.postgresql.close();

Response Handling

Framework-agnostic standardized API responses with built-in support for Express, Koa, Fastify, and Hapi:

const { responseHandler } = require("ods-utils");

// Express.js example
app.get("/api/users", (req, res) => {
  responseHandler.sendSuccess(res, { 
    message: "Users retrieved successfully", 
    data: users 
  });
});

// Koa.js example
router.get("/api/users", async (ctx) => {
  responseHandler.sendSuccess(ctx, { 
    message: "Users retrieved successfully", 
    data: users 
  });
});

// Fastify example
fastify.get("/api/users", async (request, reply) => {
  responseHandler.sendSuccess(reply, { 
    message: "Users retrieved successfully", 
    data: users 
  });
});

// Hapi example
server.route({
  method: "GET",
  path: "/api/users",
  handler: async (request, h) => {
    return responseHandler.sendSuccess(h, { 
      message: "Users retrieved successfully", 
      data: users 
    });
  }
});

// Error handling
app.use((err, req, res, next) => {
  responseHandler.sendServerError(res, {
    message: "An error occurred",
    error: err
  });
});

Custom Adapters

You can also create custom adapters for other frameworks:

const { responseHandler } = require("ods-utils");

// Create a custom adapter
const customAdapter = (res, statusCode, responseBody) => {
  // Custom implementation for your framework
  return res.writeHead(statusCode, { "Content-Type": "application/json" })
    .end(JSON.stringify(responseBody));
};

// Use the custom adapter
responseHandler.sendSuccess(res, { 
  message: "Success", 
  data: result,
  adapter: customAdapter 
});

// Or add it to the adapters collection for reuse
responseHandler.adapters.customFramework = customAdapter;

// Then use it by name
responseHandler.sendSuccess(res, { 
  message: "Success", 
  data: result,
  adapter: responseHandler.adapters.customFramework 
});

Date Utilities

Comprehensive date manipulation, formatting, parsing, and comparison utilities:

const { dateutils } = require("ods-utils");

// Format date with default format (YYYY-MM-DD)
const formattedDate = dateutils.formatDate(new Date());
console.log("Formatted date:", formattedDate);

// Format date with custom format
console.log("Custom format:", dateutils.formatDate(new Date(), "DD/MM/YYYY"));
console.log("With time:", dateutils.formatDate(new Date(), "YYYY-MM-DD HH:mm:ss"));

// Parse date strings
const parsedDate1 = dateutils.parseDate("2023-05-15");
const parsedDate2 = dateutils.parseDate("05/15/2023", "MM/DD/YYYY");
const parsedDate3 = dateutils.parseDate("15/05/2023", "DD/MM/YYYY");

// Validate date strings
console.log("Is valid date:", dateutils.isValidDate("2023-05-15")); // true
console.log("Is valid date:", dateutils.isValidDate("not-a-date")); // false

// Add time to date
const futureDate = dateutils.addTime(new Date(), 5, "days");
const nextMonth = dateutils.addTime(new Date(), 1, "month");
const nextYear = dateutils.addTime(new Date(), 1, "year");

// Subtract time from date
const pastDate = dateutils.subtractTime(new Date(), 5, "days");
const lastMonth = dateutils.subtractTime(new Date(), 1, "month");

// Compare dates
const comparison = dateutils.compareDate(new Date(), new Date(2022, 0, 1));
// Returns: 1 (first date is after second date)

// Calculate difference between dates
const diffDays = dateutils.dateDiff(new Date(2023, 0, 1), new Date(2023, 0, 15), "days");
// Returns: 14

// Get date boundaries
const startOfDay = dateutils.startOf(new Date(), "day");
const endOfDay = dateutils.endOf(new Date(), "day");
const startOfMonth = dateutils.startOf(new Date(), "month");
const endOfMonth = dateutils.endOf(new Date(), "month");

// Convenience functions
const now = dateutils.now(); // Current date and time
const today = dateutils.today(); // Today at 00:00:00
const tomorrow = dateutils.tomorrow(); // Tomorrow at 00:00:00
const yesterday = dateutils.yesterday(); // Yesterday at 00:00:00

// Get relative time description
const relativeTime = dateutils.getRelativeTime(new Date(2023, 0, 1), new Date());
// Returns: "5 months ago" (example)

// Format uptime in seconds to a human-readable string
const uptime = process.uptime();
const formattedUptime = dateutils.formatUptime(uptime);
// Returns: "2d 5h 30m 15s" (example)

Middleware

Common Express middleware functions from various modules:

const { authentication, rateLimiter, logging, responseHandler, constants } = require("ods-utils");

// Apply authentication middleware
app.use(authentication());

// Apply rate limiting middleware
// Uses constants.DEFAULT_RATE_LIMIT_WINDOW_MS (60000ms = 1 minute) as default window
app.use(rateLimiter());

// Apply rate limiting middleware with custom options
app.use(rateLimiter({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  message: "Too many requests, please try again later"
}));

// Apply request logging middleware (if available)
// Note: Check the documentation for the latest implementation

// Apply error handling middleware (if available)
// Note: Check the documentation for the latest implementation

Architecture

ODS Utils is designed with a modular architecture to provide flexibility and maintainability:

  • config: Handles loading and validating configuration from environment variables
  • logging: Provides structured logging with Winston
  • caching: Implements multiple caching strategies (Redis, in-memory) with a provider-based architecture for extensibility
  • database: Manages connections and operations for MongoDB and PostgreSQL
  • responseHandler: Standardizes API responses and error handling
  • authentication: Provides JWT-based authentication middleware
  • rateLimiter: Implements rate limiting to protect APIs from abuse
  • dateutils: Provides comprehensive date manipulation, formatting, parsing, and comparison utilities

Examples

Check out the examples directory for examples of how to use this package in your projects. The examples include:

  • Express application with all utilities integrated
  • Framework-agnostic response handlers with Express, Koa, Fastify, Hapi, and custom adapters
  • Configuration management examples
  • Logging patterns
  • Caching strategies with different providers (Redis, in-memory, custom)
  • Database connectivity with MongoDB and PostgreSQL
  • API response standardization
  • Authentication and rate limiting middleware usage
  • Date utilities for formatting, parsing, manipulation, and comparison

Development

To set up the development environment:

# Clone the repository
git clone https://gitlab.com/your-organization/ods-utils.git

# Install dependencies
cd ods-utils
npm install

# Run tests
npm test

Publishing to npm

To publish this package to the npm registry:

# Login to npm (you need an npm account)
npm login

# Run tests to ensure everything is working
npm test

# Bump the version (choose one of the following)
npm version patch # for bug fixes
npm version minor # for new features
npm version major # for breaking changes

# Publish to npm
npm publish

Note: Before publishing, make sure you have the necessary permissions to publish to the npm registry under the package name "ods-utils". If the package name is already taken, you may need to choose a different name by updating the "name" field in package.json.

Testing

The project uses Jest as the testing framework. Tests are located in the tests directory and are organized by module:

  • tests/authentication.test.js: Tests for the authentication module
  • tests/caching.test.js: Tests for the caching module (including different providers and provider architecture)
  • tests/config.test.js: Tests for the configuration module
  • tests/responseHandler.test.js: Tests for the response handler module
  • tests/logging.test.js: Tests for the logging module
  • tests/mongodb.test.js: Tests for the MongoDB database module
  • tests/postgresql.test.js: Tests for the PostgreSQL database module
  • tests/rateLimiter.test.js: Tests for the rate limiter module

To run the tests:

# Run all tests
npm test

# Run tests with coverage report
npm test -- --coverage

# Run tests for a specific module
npm test -- tests/caching.test.js

The tests use mocking to isolate the modules and test them independently without requiring external services like Redis, MongoDB, or PostgreSQL.

Test Coverage

The test suite aims to provide comprehensive coverage of all modules, including:

  • Basic functionality
  • Edge cases
  • Error handling
  • Configuration options

When contributing new features or fixing bugs, please ensure that appropriate tests are added or updated to maintain test coverage.

Contributing

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

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m "Add some amazing feature")
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

ISC