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

@rshval/back-kit

v1.1.9

Published

Backend toolkit of service factories (create*/build*), validators and Node.js API utilities with DI-friendly patterns

Downloads

1,556

Readme

@rshval/back-kit

Public npm package @rshval/back-kit with server-side utilities for Node.js/TypeScript projects.

This repository is used for the author's internal projects. Any third-party usage is at your own risk.

Installation

npm i @rshval/back-kit

The package is ESM-only ("type": "module"). For CommonJS, use dynamic import().

Quick navigation


API and usage examples

Below are the public exports from the package (via src/index.ts) with short examples. For key APIs, there are separate production examples that show practical integration patterns for real services.

1) Email

createMailOptions({ from, to, subject, text })

Creates a nodemailer mail options object. Supports to as a string (regular send) or a form object (MailOptionsBody) for requests/feedback scenarios.

import { createMailOptions } from '@rshval/back-kit';

const options = createMailOptions({
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Hello',
  text: 'Welcome!',
});

sendEmailWithConfig({ nodemailerConfig, to, subject, text })

Creates a nodemailer transport, sends an email, and returns a string with the send result.

import { sendEmailWithConfig } from '@rshval/back-kit';

await sendEmailWithConfig({
  nodemailerConfig: {
    host: 'smtp.example.com',
    port: 465,
    secure: true,
    auth: { user: '[email protected]', pass: '***' },
  },
  to: '[email protected]',
  subject: 'Reset password',
  text: 'Code: 123456',
});

Production example:

import { buildSendEmail } from '@rshval/back-kit';

const sendEmailWithConfig = buildSendEmail(runtimeConfig);
await sendEmailWithConfig(to, subject, text);

2) Config and JWT

getBaseUrlByConfig(config, baseUrl?)

Builds a base URL from app config. In development, adds :port.

import { getBaseUrlByConfig } from '@rshval/back-kit';

const base = getBaseUrlByConfig(
  {
    NODE_ENV: 'development',
    server: { domain: 'localhost', port: 3000 },
    jwt: {},
  },
  '/api',
);
// //localhost:3000/api

createTokenByConfig({ config, user, expiresIn })

Creates a JWT token based on config.jwt.JWT_KEY (or JWT_KEY_NO_ENV).

import { createTokenByConfig } from '@rshval/back-kit';

const token = createTokenByConfig({
  config: {
    server: { domain: 'example.com' },
    jwt: { JWT_KEY: 'super-secret' },
  },
  user: { _id: '64a...' },
  expiresIn: '7d',
});

3) Helper utilities

createPinCode(min?, max?)

Generates a random numeric PIN in range (10000..99990 by default).

import { createPinCode } from '@rshval/back-kit';

const pin = createPinCode();

getIp(req)

Attempts to detect client IP from req.ip, sockets, and x-forwarded-for.

import { getIp } from '@rshval/back-kit';

const ip = await getIp(req);

translitUrl(str)

Transliterates a string into a URL-friendly slug (-, lower-case).

import { translitUrl } from '@rshval/back-kit';

const slug = translitUrl('Page example');
// primer-stranicy

4) Validation

patternEmail()

Returns a RegExp for email validation.

patternPassword()

Returns a RegExp for password validation (at least 8 chars, letters + digits).

isValidEmail(val)

Checks whether an email is valid.

isValidPhoneNumber(val)

Validates a phone number via libphonenumber-js.

isValidCode(code, length)

Checks code length.

isEmpty(val)

Checks for an empty string (trim) or an empty object.

import {
  patternEmail,
  patternPassword,
  isValidEmail,
  isValidPhoneNumber,
  isValidCode,
  isEmpty,
} from '@rshval/back-kit';

const emailRegex = patternEmail();
const passwordRegex = patternPassword();

isValidEmail('[email protected]'); // true
isValidPhoneNumber('+79991234567'); // true/false
isValidCode('123456', 6); // true
isEmpty('   '); // true
isEmpty({}); // true

5) Builders (config-bound)

buildGetBaseUrl(config)

Returns a function (baseUrl?) => string.

buildCreateToken(config)

Returns a JWT creator function with pre-bound config.

buildSendEmail(nodemailerConfig)

Returns an email sender function with pre-bound SMTP config.

import {
  buildGetBaseUrl,
  buildCreateToken,
  buildSendEmail,
} from '@rshval/back-kit';

const getBaseUrl = buildGetBaseUrl({
  NODE_ENV: 'production',
  server: { domain: 'example.com' },
  jwt: { JWT_KEY: 'secret' },
});

const createToken = buildCreateToken({
  server: { domain: 'example.com' },
  jwt: { JWT_KEY: 'secret' },
});

const sendEmail = buildSendEmail({
  host: 'smtp.example.com',
  port: 465,
  secure: true,
  auth: { user: '[email protected]', pass: '***' },
});

6) Database

startMongoDatabase(options)

Starts MongoDB connection via mongoose, logs statuses, and supports connection retries.

import { startMongoDatabase } from '@rshval/back-kit';

await startMongoDatabase({
  config: {
    name: 'main',
    connect: process.env.MONGO_URI,
    params: {},
  },
  logger: console,
});

Production example:

await startMongoDatabase({
  config: config.database,
  logger,
  setCacheStatus: (status) =>
    cache.set(cacheIdDatabase, { status }, undefined, undefined, cacheTtl30m),
});

7) Cache

createCacheService(options?)

Creates an LRU cache service with methods:

  • get(key)
  • set(key, data, compareKey?, compareValue?, ttlMs?)
  • delete(key)
  • getId(val)
  • keys()
  • clear()
  • entries() (if exposeEntries: true)
  • values() (if exposeValues: true)
import { createCacheService } from '@rshval/back-kit';

const cache = createCacheService({ ttl: 60_000 });
const key = cache.getId({ service: 'users', page: 1 });
await cache.set(key, [{ s: 'state', data: [1, 2, 3] }]);
const value = await cache.get(key);

createCacheMiddleware({ cache, ... })

Creates a middleware wrapper over the cache service with methods:

  • get(id)
  • set(id, data, expDataTime)
  • del(id)
  • delByPrefix(prefix) (if includeDelByPrefix: true)
import { createCacheService, createCacheMiddleware } from '@rshval/back-kit';

const cache = createCacheService({ supportTtlInSet: true });
const cm = createCacheMiddleware({
  cache,
  passTtlToCacheSet: true,
  includeDelByPrefix: true,
});

await cm.set('users:list', [{ id: 1 }], 60_000);
const cached = await cm.get('users:list');
await cm.delByPrefix?.('users:');

Production example:

const cache = createCacheService({ supportTtlInSet: true });
const cacheMiddleware = createCacheMiddleware({
  cache,
  passTtlToCacheSet: true,
  includeDelByPrefix: true,
});

export const { get, set, del } = cacheMiddleware;
export const delByPrefix = cacheMiddleware.delByPrefix!;

8) Logging

createLoggerService({ rootdir? })

Returns a logger factory. For each namespace (std) it writes:

  • logs/<std>/stdout.log
  • logs/<std>/stderr.log
import { createLoggerService } from '@rshval/back-kit';

const makeLogger = createLoggerService({ rootdir: process.cwd() });
const logger = makeLogger('api');
logger.log('started');

Production example:

const loggerService = createLoggerService();
const logger = loggerService('api');

9) WebSocket client

createSocketClientService(options)

Creates a socket.io client service with methods:

  • doSocketClient() — start connection
  • getSocketClient() — return current instance
import { createSocketClientService } from '@rshval/back-kit';

const ws = createSocketClientService({
  wsName: 'worker',
  socketBase: 'https://example.com',
  logger: console,
  runWorkers: () => {
    // jobs
  },
});

ws.doSocketClient();

Production example:

const socketClientService = createSocketClientService({
  wsName: config.ws.name,
  socketBase: SOCKET_BASE,
  logger,
  runWorkers: socketClientWorkers,
  socketClientInterval: config.settings.socketClientInterval,
});

socketClientService.doSocketClient();

10) Paymaster

createPaymasterService({ paymaster, clientServer, serverBaseUrl })

Creates a service with methods:

  • createPaymentLink({...}) — build payment URL
  • validateCallback(payload, rawBody?) — verify callback signature
  • parseCallback(payload) — normalize callback into a convenient object
  • syncPaymentStatus({ paymentNo, merchantId? }) — safe PSP status sync (returns null on any API error), normalized status: paid | cancelled | pending | refunded
  • createRefund({ paymentNo, amount, currency, reason, merchantId? }) — request refund via provider API
import { createPaymasterService } from '@rshval/back-kit';

const paymaster = createPaymasterService({
  paymaster: {
    merchantId: 'merchant-id',
    secretKey: 'secret',
    checkoutUrl: 'https://paymaster.ru/Payment/Init',
    checkSignature: true,
    statusApiUrl: process.env.PAYMASTER_STATUS_API_URL,
    statusApiToken: process.env.PAYMASTER_STATUS_API_TOKEN,
    statusApiTimeoutMs: Number(process.env.PAYMASTER_STATUS_API_TIMEOUT_MS || 8000),
    refundApiUrl: process.env.PAYMASTER_REFUND_API_URL,
    refundApiToken: process.env.PAYMASTER_REFUND_API_TOKEN,
    refundApiTimeoutMs: Number(process.env.PAYMASTER_REFUND_API_TIMEOUT_MS || 8000),
  },
  clientServer: 'https://site.example.com',
  serverBaseUrl: 'https://api.example.com',
});

const link = paymaster.createPaymentLink({
  requestId: 'order_123',
  amount: 1499,
  description: 'Order #123',
});

const synced = await paymaster.syncPaymentStatus({
  paymentNo: link.paymentNo,
});

if (!synced) {
  // Safe fallback: keep local status unchanged or schedule retry
} else {
  // status: 'paid' | 'cancelled' | 'pending' | 'refunded'
  console.log(synced.status, synced.statusRaw);
}

const refund = await paymaster.createRefund({
  paymentNo: link.paymentNo,
  amount: 1499,
  reason: 'Customer requested cancellation',
  // optional
  currency: 'RUB',
});

if (!refund.success) {
  console.error(refund.error, refund.httpStatus, refund.statusRaw);
}

Status API environment variables:

  • PAYMASTER_STATUS_API_URL
  • PAYMASTER_STATUS_API_TOKEN
  • PAYMASTER_STATUS_API_TIMEOUT_MS

Refund API environment variables:

  • PAYMASTER_REFUND_API_URL
  • PAYMASTER_REFUND_API_TOKEN
  • PAYMASTER_REFUND_API_TIMEOUT_MS

Production example:

export const paymasterService = createPaymasterService({
  paymaster: config.platforms.paymaster,
  clientServer: config.clientServer,
  serverBaseUrl: config.server.baseUrl,
});

11) Mail templates

createMailTemplateService({ findTemplate, sendEmail })

Creates an email template service with methods:

  • extractVariables(template) — list of {{variables}}
  • renderTemplate(template, context?) — render subject/body
  • sendByKey({ key, to, context? }) — find template, render, and send
import { createMailTemplateService } from '@rshval/back-kit';

const mailTemplates = createMailTemplateService({
  findTemplate: async ({ key }) =>
    key === 'welcome'
      ? { subject: 'Hi, {{user.name}}', bodyText: 'Hello {{user.name}}!' }
      : null,
  sendEmail: async (to, subject, text) => {
    console.log('send', to, subject, text);
  },
});

await mailTemplates.sendByKey({
  key: 'welcome',
  to: '[email protected]',
  context: { user: { name: 'Alex' } },
});

Production example:

const sendEmailWithConfig = buildSendEmail(runtimeConfig);

export const mailTemplateService = createMailTemplateService({
  findTemplate: ({ key }) => MailTemplate.findOne({ key, isActive: true }),
  sendEmail: sendEmailWithConfig,
});

12) Audit changes

buildAuditChanges({ beforeData, afterData, fieldsToCheck, protectedFields? })

Compares before/after data and returns an array of changes for selected fields.

createAuditLog({ ..., save })

Creates an audit record via provided save function. Returns null when no changes exist.

import { buildAuditChanges, createAuditLog } from '@rshval/back-kit';

const changes = buildAuditChanges({
  beforeData: { name: 'Old', role: 'user' },
  afterData: { name: 'New', role: 'user' },
  fieldsToCheck: ['name', 'role'],
  protectedFields: ['role'],
});

await createAuditLog({
  entityType: 'user',
  entityId: '507f1f77bcf86cd799439011',
  action: 'update',
  changedBy: '507f191e810c19729de860ea',
  changes,
  save: async (payload) => payload,
});

Production example:

await createAuditLog({
  entityType,
  entityId,
  action,
  changedBy,
  changes,
  meta,
  save: async (payload) => AuditLog.create(payload),
});

13) Seed functions

createSeedFunctions({ cache, retryDelayMs? })

Returns methods:

  • checkDatabaseIsConnected() — checks DB state via cache
  • setSeedData(SeedModel, arr) — inserts seed data after connection check
import { createSeedFunctions, createCacheService } from '@rshval/back-kit';

const cache = createCacheService();
const { setSeedData } = createSeedFunctions({ cache });

// await setSeedData(UserModel, [{ name: 'Admin' }])

Production example:

export const { checkDatabaseIsConnected, setSeedData } = createSeedFunctions({
  cache,
});

14) API client

createApiService({ userAgent, logger? })

Returns an HTTP client with methods:

  • get(path, token?)
  • getXml(path, token?)
  • del(path, token?)
  • post(path, data, token?, xml?, contentType?)
  • put(path, data, token)
import { createApiService } from '@rshval/back-kit';

const api = createApiService({
  userAgent: 'my-service/1.0.0',
  logger: console,
});

const users = await api.get('https://api.example.com/users');
const created = await api.post('https://api.example.com/users', {
  name: 'Alex',
});

Production example:

const apiService = createApiService({
  userAgent: config.api.userAgent,
  logger,
});

export const { get, getXml, del, post, put } = apiService;

Token type is also exported:

import type { Token } from '@rshval/back-kit';

15) Other exported utilities

add(a, b)

Returns the sum of two numbers.

test2()

Logs 99 and returns 8.

import { add, test2 } from '@rshval/back-kit';

add(2, 3); // 5
test2(); // 8

Preparing for npm publication

See detailed guide: docs/publishing.md.

Short wording for npm description:

  • A set of service factories (create*, build*) and ready-to-use utilities/validators.
  • DI-friendly API: dependencies are injected externally (logger, cache, save, findTemplate).
  • Important behavior options (supportTtlInSet, passTtlToCacheSet, includeDelByPrefix) should be documented near examples.

Development (standalone)

npm install
npm run build

Exports

  • ESM: dist/index.js
  • Types: dist/index.d.ts