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

rm-mapepire-js

v0.2.0

Published

Wrapper over the IBM Mapepire DB2 client for Node.js

Readme

rm-mapepire-js

A TypeScript wrapper over the IBM Mapepire DB2 client for Node.js, providing connection pooling and management for IBM i databases.

Why rm-mapepire-js?

The base @ibm/mapepire-js package provides a WebSocket-based DB2 client for IBM i — but it leaves connection lifecycle management, pooling strategy, and production concerns up to you. rm-mapepire-js builds on top of it to deliver a production-ready experience:

  • Enterprise Connection Pooling — Auto-scaling pools with configurable min/max sizing, on-demand growth, and batch connection creation. The base package has a basic pool; this library adds tiered connection management with separate policies for initial vs. overflow connections.

  • Automatic Connection Expiry — Idle overflow connections are automatically retired after a configurable timeout, freeing IBM i jobs during low-activity periods. Initial connections can be set to persist indefinitely.

  • Health Checks with Transparent Retry — Connections are validated before being handed out (VALUES 1 probe). Unhealthy connections are silently retired and replaced, so your application code never sees a stale connection.

  • Thread-Safe Attach — A promise-chain mutex serializes connection checkout, preventing race conditions when multiple callers request connections simultaneously.

  • Multi-Pool Management — Run up to 8 isolated pools (e.g., production, reporting, batch) under a single RmPools manager with independent configuration, credentials, and lifecycle.

  • Init Commands — Automatically execute CL commands or SQL statements on every new connection (set library lists, environment variables, job attributes) so connections are ready to use immediately.

  • Event-Driven LifecycleRmPool extends EventEmitter with 8 lifecycle events (connection:created, connection:expired, pool:exhausted, etc.) for monitoring, metrics, and orchestration.

  • Injectable Logging — Plug in your own logger (Winston, Pino, etc.) via a simple interface. Logs flow hierarchically through the entire class chain with structured service metadata.

  • Hardened Error Handling — Pool operations are wrapped with contextual error information (pool ID, connection index, job name) and graceful degradation, so a single bad connection doesn't take down your pool.

  • TypeScript-First — Full type coverage with exported interfaces for all configuration, making misconfiguration a compile-time error rather than a runtime surprise.

Installation

npm install rm-mapepire-js

Prerequisites

This package requires a Mapepire server running on your IBM i. See @ibm/mapepire-js for details.

Install from GitHub (alternative)

# Latest stable release
npm install github:richardm90/rm-mapepire-js#main

# Development branch
npm install github:richardm90/rm-mapepire-js#dev

Usage

Basic Setup

import { RmPools } from 'rm-mapepire-js';

const poolsConfig = {
  debug: true,
  activate: true,
  pools: [
    {
      id: 'myPool',
      PoolOptions: {
        creds: {
          host: 'your-host',
          user: 'your-user',
          password: 'your-password',
          rejectUnauthorized: false,
        },
        maxSize: 20,
        initialConnections: {
          size: 8,
          expiry: 30 // minutes
        },
        JDBCOptions: {
          libraries: "RMDATA"
        }
      }
    }
  ]
};

const pools = new RmPools(poolsConfig);
await pools.init();

Using a Connection

Direct Pool Query (Recommended)

The simplest way to execute queries - the pool automatically handles connection lifecycle:

// Get a pool
const pool = await pools.get('myPool');

// Execute a query directly on the pool (auto attach/detach)
const result = await pool.query('SELECT * FROM MY_TABLE');

// With query options
const result = await pool.query('SELECT * FROM MY_TABLE WHERE id = ?', {
  parameters: [123]
});

Manual Connection Management

For more control, you can manually attach and detach connections:

// Get a pool
const pool = await pools.get('myPool');

// Attach a connection
const connection = await pool.attach();

// Execute a query
const result = await connection.query('SELECT * FROM MY_TABLE');

// Detach the connection (return to pool)
await pool.detach(connection);

Configuration Options

Pool Options

  • creds: Database credentials object - a standard Mapepire DaemonServer object
  • maxSize: Maximum number of connections in the pool (default: 20)
  • initialConnections: Initial connection settings
    • size: Number of connections to create on initialization (default: 8)
    • expiry: Connection expiry time in minutes (default: null). Set to null or omit for connections that never expire. A value of 0 is treated the same as null (no expiry). Only positive values start an expiry timer.
  • incrementConnections: Settings for dynamically added connections
    • size: Number of connections to add when pool is exhausted (default: 8)
    • expiry: Expiry time for new connections in minutes (same rules as above)
  • dbConnectorDebug: Enable debug logging (default: false)
  • JDBCOptions: JDBC options object - a standard Mapepire JDBCOptions object
  • initCommands: Array of commands to execute when each connection is initialized. Each entry is an object with command (string) and optional type ('cl' or 'sql', defaults to 'cl'). CL commands are executed via QCMDEXC with parameterised input; SQL commands are executed directly via job.execute() without parameterisation. Security note: SQL-type init commands must be trusted, developer-supplied strings — never pass unsanitised user input as an init command.
  • healthCheck: Health check settings
    • onAttach: Verify connections are alive before returning from attach() by executing a lightweight query (VALUES 1). Unhealthy connections are automatically retired and replaced. (default: true). Set to false to disable.
  • logger: Custom logger object (per-pool override, see Logger below)

Pools Options

  • activate: Auto-activate pools on registration (default: true)
  • debug: Enable debug logging (default: false)
  • pools: Array of pool configurations
  • logger: Custom logger object implementing the Logger interface. Flows down to all pools and connections. Defaults to a built-in console logger.

Logger

All classes accept an optional logger that implements the Logger interface:

interface Logger {
  log(level: string, message: string, meta?: any): void;
}

The logger flows down from RmPoolsRmPoolRmPoolConnectionRmConnection. You can set it at the top level or per-pool:

import { RmPools } from 'rm-mapepire-js';

// Custom logger (e.g. winston, pino, or any object with a log method)
const myLogger = {
  log(level, message, meta) {
    // Send to your logging infrastructure
    console.log(`[${level}] ${message}`, meta);
  }
};

const pools = new RmPools({
  logger: myLogger,  // All pools and connections use this logger
  pools: [{ id: 'myPool', PoolOptions: { creds: { ... } } }]
});

For standalone connections (without pools):

import { RmConnection } from 'rm-mapepire-js';

const conn = new RmConnection(creds, jdbcOptions, [], false, myLogger);
await conn.init();

Quick Start: Winston

Winston's log(level, message, meta) method matches the Logger interface directly, so a Winston logger can be passed in as-is:

import winston from 'winston';
import { RmPools } from 'rm-mapepire-js';

const logger = winston.createLogger({
  level: 'debug',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'db.log' })
  ]
});

const pools = new RmPools({
  debug: true,
  logger,
  pools: [
    {
      id: 'myPool',
      PoolOptions: { creds: { host: '...', port: 8076, user: '...', password: '...' } }
    }
  ]
});

await pools.init();

All pool and connection activity will now flow through Winston — no adapter needed.

API Reference

RmPools

Main class for managing multiple connection pools.

Methods

  • init(): Initialize all registered pools
  • register(poolConfig): Register a new pool configuration
  • get(poolId?): Get a pool by ID (returns first pool if ID not provided)
  • attach(pool): Attach a connection from the pool
  • close(): Close all active pools and mark them inactive
  • connectionDiag(poolId, connection, sql): Log connection diagnostics
  • getInfo(): Get information about all pools for debugging
  • printInfo(): Print all pools info to console
  • printStats(): Print summary statistics for all pools

RmPool

Manages a pool of database connections. Extends EventEmitter.

Methods

  • init(): Initialize the pool with initial connections
  • query(sql, opts?): Execute a SQL query using a connection from the pool (automatically handles attach/detach)
  • attach(): Get an available connection from the pool
  • detach(connection): Return a connection to the pool
  • retire(connection): Remove a connection from the pool permanently
  • detachAll(): Return all connections to the pool
  • retireAll(): Remove all connections from the pool
  • close(): Close all connections in the pool (alias for retireAll())
  • getInfo(): Get detailed pool information for debugging
  • getStats(): Get pool statistics summary
  • printInfo(): Print detailed pool information to console
  • printStats(): Print pool statistics to console

Events

  • pool:initialized — Pool init complete. Payload: { poolId, connections }
  • connection:created — New connection added. Payload: { poolId, poolIndex, jobName }
  • connection:attached — Connection handed to consumer. Payload: { poolId, poolIndex }
  • connection:detached — Connection returned to pool. Payload: { poolId, poolIndex }
  • connection:retired — Connection removed from pool. Payload: { poolId, poolIndex }
  • connection:expired — Expiry timer fired. Payload: { poolId, poolIndex }
  • connection:healthCheckFailed — Health check failed before retire. Payload: { poolId, poolIndex }
  • pool:exhausted — Max connections reached. Payload: { poolId, maxSize }
const pool = await pools.get('myPool');
pool.on('connection:created', ({ poolId, poolIndex, jobName }) => {
  console.log(`New connection ${poolIndex} created (job: ${jobName})`);
});
pool.on('pool:exhausted', ({ poolId, maxSize }) => {
  console.warn(`Pool ${poolId} exhausted at ${maxSize} connections`);
});

RmPoolConnection

Represents a single pooled database connection.

Methods

  • query(sql, opts?): Execute a SQL query
  • detach(): Mark the connection as available and return it
  • retire(): Close and retire the connection
  • isAvailable(): Check if the connection is available
  • isHealthy(): Check if the underlying connection is still alive (executes VALUES 1)
  • getStatus(): Get the current status of the underlying job
  • getInfo(): Get connection information for debugging
  • printInfo(): Print connection info to console

RmConnection

Represents a standalone database connection (not pooled).

Methods

  • init(): Initialize the connection and connect to the database
  • execute(sql, opts?): Execute a SQL statement
  • query(sql, opts?): Execute a SQL query (alias for execute)
  • close(): Close the connection
  • getStatus(): Get the current status of the underlying job
  • getInfo(): Get connection information for debugging
  • printInfo(): Print connection info to console

License

ISC

Author

Richard Moulton

Updating to the latest version

npm update rm-mapepire-js

Releasing

This project uses npm version for versioning. Versions follow semver.

# 1. Merge dev into main
git checkout main
git merge dev

# 2. Bump version (choose one)
npm version patch   # 0.1.0 → 0.1.1 (bug fixes)
npm version minor   # 0.1.0 → 0.2.0 (new features)
npm version major   # 0.1.0 → 1.0.0 (breaking changes)

# 3. Push with tags
git push origin main --follow-tags

# 4. Publish to npm
npm publish

# 5. Return to dev
git checkout dev
git merge main
git push origin dev

Use npm link for Active Development

If you're making frequent changes, npm link is faster:

# In your rm-mapepire-js directory
npm link

# In your consuming project
npm link rm-mapepire-js

Now any changes you make and build in rm-mapepire-js are immediately available.

When done:

# 1. In your consuming project - removes the symlink
npm unlink rm-mapepire-js

# 2. In your rm-mapepire-js directory - removes the global link
npm unlink

# 3. In your consuming project - reinstall normally
npm install rm-mapepire-js
# Check if something is linked, in the consuming project
cd test-rm-mapepire-js
ls -l node_modules/ | grep "^l"