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

@incloodsolutions/node-toolkit

v0.0.20

Published

A toolkit containing utility, helper, config, interfaces for nodejs apps

Readme

@incloodsolutions/node-toolkit

npm version npm downloads license

Server-side helpers built on top of @incloodsolutions/toolkit: serverless adapters for Express/NestJS, AWS SDK v3 wrappers, Mongoose helpers tuned for serverless, crypto and hashing, environment-variable loading, request logging, and API-response utilities.

For a one-line index of every export in this package (and the other toolkits), see ../docs/AI-INDEX.md. Every exported symbol also carries an inline TSDoc comment with parameter descriptions, default values, and examples.


Installation

npm install @incloodsolutions/node-toolkit

Requires Node.js 22+. AWS SDK v3 clients, @codegenie/serverless-express, mongoose, bcryptjs, crypto-js, class-validator, class-transformer, morgan, bwip-js, and uuid are installed as dependencies. Every dependency is kept external (not bundled) so the ESM build stays loadable — bundling mongoose would pull the MongoDB driver's dynamic require() calls into the bundle and break ESM consumers.

express is not a dependency: it is only ever used as a type (import type { Request } from 'express'), so it is erased from the build. A serverless host (Nest, or @codegenie/serverless-express) brings its own Express.

Every subpath ships both formats (like the other toolkits): import resolves to ESM, require to CommonJS, each with its own .d.ts. Every bundle is verified to load in a real ESM runtime by test/esm-bundle.spec.ts.

Modular imports (tree-shaking)

There is no package-root import. import ... from '@incloodsolutions/node-toolkit' does not resolve — you must import a specific subpath, so nothing can pull the whole package (the AWS SDK, Mongoose, bwip-js, …) by accident. Each area is published as its own subpath, down to the individual AWS service: @incloodsolutions/node-toolkit/aws-sdk/s3 pulls only @aws-sdk/client-s3, not the DynamoDB client or its Zod validation chain.

import { initLambdaFunctionHandler } from '@incloodsolutions/node-toolkit/aws-lambda';
import { initS3ClientWrapper } from '@incloodsolutions/node-toolkit/aws-sdk/s3';
import { initGcpFunctionHandler } from '@incloodsolutions/node-toolkit/gcp';
import { initMongooseConnection, initMongooseSchema } from '@incloodsolutions/node-toolkit/mongo';
import { encryptData, generateCustomUUID } from '@incloodsolutions/node-toolkit/utility';
import { initEnvironmentVariables } from '@incloodsolutions/node-toolkit/config';
import type { IBaseApiResult } from '@incloodsolutions/node-toolkit/interface';

| Subpath | Contents | | ------- | -------- | | .../aws | everything AWS: Lambda adapter + all SDK wrappers | | .../aws-lambda | initLambdaFunctionHandler, getCurrentLambdaInvocation | | .../aws-cli | uploadToS3ViaCli (placeholder) | | .../aws-sdk | all SDK wrappers (S3, SES, SNS, SSM, DynamoDB, EventBridge) | | .../aws-sdk/s3 | initS3ClientWrapper | | .../aws-sdk/ses | initSesClientWrapper | | .../aws-sdk/sns | initSnsClientWrapper | | .../aws-sdk/parameter | initSsmParameterClientWrapper | | .../aws-sdk/dynamo-db | initDynamoDbClientWrapper | | .../aws-sdk/event-bridge | initEventBridgeClientWrapper (placeholder) | | .../gcp | initGcpFunctionHandler | | .../mongo | initMongooseConnection, initMongooseSchema | | .../utility | crypto/hashing, Lambda /tmp IO, IDs, API-response and logging helpers, class-validator helpers, Mongoose normalisers, QR/barcode | | .../config | initEnvironmentVariables | | .../interface | IBaseEnvironmentVariable, IBaseApiResult, IBaseMongoDocument, MongoIdType, SortOrderType |

Every subpath resolves ESM (import), CommonJS (require), and its own .d.ts.

What's inside

| Area | Exports | | ---- | ------- | | Serverless adapters | initLambdaFunctionHandler, getCurrentLambdaInvocation, initGcpFunctionHandler | | AWS SDK wrappers | initS3ClientWrapper, initSesClientWrapper, initSnsClientWrapper, initSsmParameterClientWrapper, initDynamoDbClientWrapper | | Config | initEnvironmentVariables | | MongoDB / Mongoose | initMongooseConnection, initMongooseSchema | | Crypto & hashing | encryptData, decryptData, hashWithBcrypt, validateHashWithBcrypt | | Lambda filesystem | writeFileToLambda, readFileFromLambda, isLambdaEnvironment | | IDs | generateCustomUUID, isValidUUID, isValidMongoId | | HTTP / API | apiResult, returnApiResponse, returnApiOverview, getIpAddress, reqResLogger, encodeUrlComponent, decodeUrlComponent | | Logging | initCustomLogger | | Validation | validateDataWithClassValidator | | Mongo data shaping | normalizeMongooseData, normalizeMongooseData_v2, sanitizeObject | | Misc | generateQrBarcode, isNestApplication | | Interfaces / types | IBaseEnvironmentVariable, IBaseApiResult, IBaseMongoDocument, INestAppInstance, MongoIdType, SortOrderType |

Not yet implemented: initEventBridgeClientWrapper (returns {}), uploadToS3ViaCli (empty). BaseSchemaEntity exists in source but is not exported.

Usage

Run an Express or NestJS app on AWS Lambda

import { initLambdaFunctionHandler } from '@incloodsolutions/node-toolkit/aws-lambda';
import { app } from './app'; // an Express instance or a NestJS app instance

export const handler = (event: any, context: any, callback: any) =>
  initLambdaFunctionHandler({ app, event, context, callback });

getCurrentLambdaInvocation() returns the current { context, event } anywhere downstream. The equivalent for Google Cloud Functions is initGcpFunctionHandler({ app, request, response }).

Load and validate environment variables (no dotenv)

import { initEnvironmentVariables } from '@incloodsolutions/node-toolkit/config';

export const env = initEnvironmentVariables(
  {
    NODE_ENV: { required: true, defaultValue: 'development' },
    PORT: { defaultValue: 8080 },
    MONGO_DATABASE_URL: { required: true },
  },
  { enableDebug: true },
);

A required variable with no value and no defaultValue throws a CustomException.

SSM Parameter Store

import { initSsmParameterClientWrapper } from '@incloodsolutions/node-toolkit/aws-sdk/parameter';

const ssm = initSsmParameterClientWrapper();

const dbPassword = await ssm.getParameter({ name: '/my-app/db-password' });

const { values, invalidParameterNames } = await ssm.getParameters({
  names: ['/my-app/db-password', '/my-app/api-key'],
});

// Every parameter under a path, with pagination handled for you.
const config = await ssm.getParametersByPath({ path: '/my-app/' });

SecureString parameters are decrypted by default (withDecryption: true).

DynamoDB document-client wrapper

import { initDynamoDbClientWrapper } from '@incloodsolutions/node-toolkit/aws-sdk/dynamo-db';

const users = initDynamoDbClientWrapper<UserRecord, 'emailIndex'>({
  tableName: 'users',
  schema: UserSchema, // a Zod object schema
  compositePrimaryKeyOptions: { primaryKeyName: 'id', primaryKeyIdType: 'uuid' },
  options: { timestamp: true, enableDebug: false },
});

await users.put({ data: { name: 'Ada', email: '[email protected]' } });
const { data, nextPageToken } = await users.query({
  conditions: { email: '[email protected]' },
  filter: {},
  indexName: 'emailIndex',
  returnAll: true,
});
await users.updateOne({ key: { id }, data: { name: 'Ada L.' } });
await users.delete({ key: { id } });

The wrapper automatically escapes any of DynamoDB's ~573 reserved words (matched case-insensitively) used as an attribute name in conditions, filter, searchTerms, or updateOne's data, plus projection (select), contains search (searchTerms), and automatic pagination when returnAll is set.

S3, SES, SNS

import { initS3ClientWrapper } from '@incloodsolutions/node-toolkit/aws-sdk/s3';
import { initSesClientWrapper } from '@incloodsolutions/node-toolkit/aws-sdk/ses';
import { initSnsClientWrapper } from '@incloodsolutions/node-toolkit/aws-sdk/sns';

const s3 = initS3ClientWrapper({ bucketName: 'assets' });
const url = await s3.generateSignedUrl({ fileName: 'a.png', commandType: 'read', expiresIn: 900 });

const ses = initSesClientWrapper({ sourceEmail: '[email protected]' });
await ses.sendEmail({ subject: 'Hi', message: { content: '<b>Hello</b>' }, receivers: ['[email protected]'] });

const sns = initSnsClientWrapper({ config: { region: 'us-east-1' } });
await sns.sendSms({ message: 'Code 1234', phoneNumber: '+15550000000' });

Mongoose in serverless

import { initMongooseConnection, initMongooseSchema } from '@incloodsolutions/node-toolkit/mongo';

const { connection, closeConnection } = await initMongooseConnection({
  options: { retries: 5, retryDelayMs: 5000, enableDebug: true },
});

const UserSchema = initMongooseSchema<UserModel>({ name: String, email: String });

The connection is cached on global and reused across warm Lambda invocations.

Crypto, hashing, IDs

import {
  encryptData, decryptData,
  hashWithBcrypt, validateHashWithBcrypt,
  generateCustomUUID,
} from '@incloodsolutions/node-toolkit/utility';

const token = encryptData({ data: { userId: 1 }, secret: process.env.SECRET, type: 'aes256' });
const payload = decryptData<{ userId: number }>({ hashedData: token, secret: process.env.SECRET });

const hash = await hashWithBcrypt('password', 10);
const ok = await validateHashWithBcrypt('password', hash);

const id = generateCustomUUID({ version: 7, asUpperCase: true });

API responses and logging

import {
  returnApiResponse, apiResult, returnApiOverview,
  reqResLogger, initCustomLogger,
} from '@incloodsolutions/node-toolkit/utility';

app.use(reqResLogger({ formats: ['user-agent'] }));
app.get('/', (_req, res) => res.send(returnApiOverview({ name: 'My API', docsUrl: '/docs' })));
app.get('/users', (_req, res) => returnApiResponse(res, apiResult({ data: users }), 200));

Normalising Mongoose documents for API output

import { normalizeMongooseData_v2 } from '@incloodsolutions/node-toolkit/utility';

const user = normalizeMongooseData_v2(await UserModel.findById(id));
// ObjectIds become strings recursively; `id` is added from `_id`.

QR codes and barcodes

import { generateQrBarcode } from '@incloodsolutions/node-toolkit/utility';

const qr = await generateQrBarcode('https://inclood.io');            // data:image/png;base64,...
const barcode = await generateQrBarcode({ id: 42 }, { type: 'barcode' });

Development

npm install
npm run build      # tsup: one ESM + CJS + .d.ts bundle per subpath entry
npm run format     # prettier --write (tabs, single quotes, trailing commas)
npm run lint       # eslint --fix
npm test           # vitest run — behaviour tests for every export
npm run test:watch # vitest in watch mode
npm run package    # build, then npm pack a tarball

Tests live in test/ (utility / aws / lambda / platform). AWS SDK clients are stubbed with aws-sdk-client-mock, @codegenie/serverless-express and mongoose.connect are mocked, bwip-js and fs are mocked for the Lambda helpers — nothing touches the network or a database. Each file's header comment lists the utilities that are currently buggy.

The whole build is tsup (dts: true), pinned to typescript@^6. tsconfig.json uses moduleResolution: "bundler" with customConditions: ["node"] so packages that expose their types only through a node export condition (e.g. bwip-js) resolve.

The published package is ESM-first ("type": "module"). It has no root export and no main/module/types fields — every entry point is a subpath in exports, each wiring up import (ESM), require (CommonJS), and types. The index bundle is still built as the test aggregation point but is not reachable by the package name.

License

MIT © Inclood Solutions