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

@x12i/helpers

v1.7.0

Published

Small helper utilities for x12i projects.

Readme

@x12i/helpers

Small helper utilities for x12i projects.

Install

npm i @x12i/helpers

Helpers (library of abilities)

Each helper has a focused doc page under helpers-docs/:

  • Objects mapper: helpers-docs/objects-mapper.md
  • HTTP tools: helpers-docs/http-tools.md
  • API contracts: helpers-docs/api-contracts.md
  • API mapper / protocol bridge: helpers-docs/api-mapper.md
  • Firebase RTDB (mongo-like): helpers-docs/firebase-rtdb.md
  • Firebase Firestore (admin init + databaseId): helpers-docs/firebase-firestore.md
  • Google Cloud Storage (object I/O): helpers-docs/gcs.md
  • MongoDB (mongo-like collection API): helpers-docs/mongo.md
  • Amazon S3 (object I/O, GCS-shaped API): helpers-docs/s3.md

Usage

Objects mapper

const { mapObject, createMapper, mapArray, deepGet, deepSet } = require("@x12i/helpers");

const source = { user: { first: "Jane", last: "Doe" } };

const mapping = [
  "user.first -> profile.firstName",
  "user.last -> profile.lastName",
  { template: "{user.first} {user.last}", to: "profile.displayName" }
];

console.log(mapObject(source, mapping));
// { profile: { firstName: 'Jane', lastName: 'Doe', displayName: 'Jane Doe' } }

You can also import the mapper directly:

const { mapObject } = require("@x12i/helpers/objects-mapper");

HTTP tools (request ⇄ curl, base URLs)

const {
  requestToCurl,
  curlToRequest,
  buildUrl,
  createBaseUrlClient,
} = require("@x12i/helpers");

const curl = requestToCurl({
  method: "POST",
  url: "https://api.example.com/v1/users",
  headers: { authorization: "Bearer TOKEN" },
  body: { name: "Jane" },
});

// curl -X POST -H 'authorization: Bearer TOKEN' -H 'content-type: application/json' --data-raw '{"name":"Jane"}' 'https://api.example.com/v1/users'
console.log(curl);

const req = curlToRequest(curl);
// { method: 'POST', url: 'https://api.example.com/v1/users', headers: { authorization: 'Bearer TOKEN', 'content-type': 'application/json' }, body: '{"name":"Jane"}' }
console.log(req);

console.log(buildUrl("https://api.example.com/", "/v1/users", { limit: 10, tags: ["a", "b"] }));
// https://api.example.com/v1/users?limit=10&tags=a&tags=b

const api = createBaseUrlClient("https://api.example.com/", {
  headers: { authorization: "Bearer TOKEN" },
});
console.log(api.curl("/v1/health"));

Direct import:

const { requestToCurl } = require("@x12i/helpers/http-tools");

API contracts + protocol bridge

Define protocol-aware API contracts (REST/GraphQL/JSON-RPC/SOAP/custom) with optional request/response validation and auth application.

const { defineContract, createRegistry } = require("@x12i/helpers/api-contracts");
const { createBridge } = require("@x12i/helpers/api-mapper");

const registry = createRegistry();

registry.register({
  name: "restGetUser",
  protocol: "rest",
  endpoint: "/api/users/{id}",
  method: "GET",
  auth: { type: "bearer" },
});

registry.register({
  name: "gqlGetUser",
  protocol: "graphql",
  endpoint: "https://api.example.com/graphql",
  query: "query GetUser($userId: ID!) { user(id: $userId) { id fullName } }",
  auth: { type: "bearer" },
});

const bridge = createBridge({
  source: "restGetUser",
  target: "gqlGetUser",
  registry,
  requestMapping: [{ from: "pathParams.id", to: "variables.userId" }],
  responseMapping: ["user.id", "user.fullName -> user.name"],
  credentials: { target: { token: "TOKEN" } },
});

// bridge.call({ pathParams: { id: "42" } })

Direct imports:

const { createBridge, batchCall, chainBridges } = require("@x12i/helpers/api-mapper");
const { defineContract, createRegistry } = require("@x12i/helpers/api-contracts");

Firebase Realtime Database (native) — mongo-like helper

This helper uses the Firebase Admin SDK and wraps RTDB with a familiar Mongo-ish API (findOne, insertOne, updateOne, etc.).

This is not a Firestore helper. If your upstream app uses Firestore, you should initialize firebase-admin with service account credentials and use admin.firestore() (Firestore does not use FIREBASE_DATABASE_URL).

  1. Create .env (see .env.example) and provide:
  • GOOGLE_SERVICE_ACCOUNT_BASE64: Base64-encoded Google service account JSON
  • FIREBASE_DATABASE_URL: the exact Realtime Database URL for that same Firebase project (copied from Firebase Console → Realtime Database → Data)

Credentials (Base64 only)

All helpers use a Base64-encoded Google service account JSON.

Why:

  • Works in serverless / edge environments
  • No filesystem dependency
  • Safer secret handling

How to generate:

cat service-account.json | base64

Then set:

GOOGLE_SERVICE_ACCOUNT_BASE64=...

Migration

Before:

FIREBASE_SERVICE_ACCOUNT_PATH=.secrets/firebase-service-account.json

After:

cat .secrets/firebase-service-account.json | base64
GOOGLE_SERVICE_ACCOUNT_BASE64=<result>
  1. Use it:
const { initFirebaseRtdb } = require("@x12i/helpers/firebase-rtdb");

const fb = initFirebaseRtdb(); // loads .env by default
const users = fb.collection("users");

const { insertedId } = await users.insertOne({ email: "[email protected]", name: "Ami" });
const user = await users.findOne({ _id: insertedId });

await users.updateOne({ _id: insertedId }, { $set: { name: "Ami N." }, $inc: { loginCount: 1 } });
await users.deleteOne({ _id: insertedId });

Important:

  • Service account + RTDB URL must match the same Firebase project.
  • Do not guess the RTDB URL (firebaseio.com vs firebasedatabase.app, region, etc.). In Firebase Console, open the project referenced by your service account JSON (project_id), then copy the Database URL shown under Realtime Database → Data and set FIREBASE_DATABASE_URL to that exact value.

Optional: to fail fast (avoid long hangs in test suites) set FIREBASE_CONNECT_TIMEOUT_MS or pass connectTimeoutMs:

const fb = initFirebaseRtdb({ connectTimeoutMs: 5000 });

If you want native RTDB query features (server-side indexed filtering), use query():

const result = await users
  .query({ orderByChild: "email", equalTo: "[email protected]", limitToFirst: 10 })
  .find();

Firebase Firestore — admin helper

If you want Firestore (not RTDB), use this helper. Firestore does not require a database URL; it authenticates via service account credentials.

  1. Set GOOGLE_SERVICE_ACCOUNT_BASE64 (Base64-encoded service account JSON).

  2. Ensure Firestore exists for that project:

  • Firebase Console → Firestore DatabaseCreate database (this creates the default database for the project)
  1. Use it:
const { initFirebaseFirestore } = require("@x12i/helpers/firebase-firestore");

const { firestore } = initFirebaseFirestore(); // loads .env by default
const docRef = firestore.doc("catalogs/appId");

await docRef.set({ hello: "world" }, { merge: true });
const snap = await docRef.get();
console.log(snap.exists, snap.data());

Optional: fail fast (avoid long hangs in test suites) set FIRESTORE_CONNECT_TIMEOUT_MS (or FIREBASE_CONNECT_TIMEOUT_MS) or pass connectTimeoutMs:

const fb = initFirebaseFirestore({ connectTimeoutMs: 5000 });

Defaults:

  • FIRESTORE_DATABASE_ID defaults to catalox
  • FIREBASE_PROJECT_ID defaults to x12i (normally inferred from the service account’s project_id, but you can override it)

If you want a different Firestore database id, set FIRESTORE_DATABASE_ID or pass databaseId:

initFirebaseFirestore({ databaseId: "catalox" });

Google Cloud Storage (GCS)

Server-side object storage only: import the subpath @x12i/helpers/gcs so the main package entry does not load @google-cloud/storage.

  1. Set GOOGLE_SERVICE_ACCOUNT_BASE64 (Base64-encoded service account JSON).

  2. Set a bucket name (defaults to storage_bucket; STORAGE_BUCKET / GCS_BUCKET also supported) or pass { bucket }.

  3. Minimal usage:

const { createGcsClient } = require("@x12i/helpers/gcs");

const gcs = createGcsClient({
  // envPath defaults to ".env"; loads GCS_BUCKET / GCS_OBJECT_PREFIX if set
  prefix: "my-app/uploads",
});

await gcs.uploadObject("user/1/avatar.png", buffer, { contentType: "image/png" });
const data = await gcs.readObjectBuffer("user/1/avatar.png", { maxBytes: 2 * 1024 * 1024 });
const { items, nextPageToken } = await gcs.listObjects({ prefix: "user/1/", maxResults: 50 });

When to use this helper instead of @google-cloud/storage directly:

  • You want shared x12i conventions for loading .env and service account material (same Base64-only credential mechanism as RTDB/Firestore helpers).
  • You want small, stable helpers for upload, buffered read (with a max size), list pagination, existence checks, and metadata, plus typed errors (GcsNotFoundError, GcsPermissionDeniedError, GcsFailedPreconditionError) for mapping to your own issue types.

Optional emulator (CI or local): set STORAGE_EMULATOR_HOST (for example with fake-gcs-server). See test/gcs.emulator.test.js for an example command line.

Live tests in this repo: set STORAGE_LIVE_TESTS=1 (or legacy GCS_LIVE_TESTS=1) and STORAGE_BUCKET (or GCS_BUCKET) to a dedicated test bucket; see test/gcs.live.test.js.

MongoDB (mongo-like, RTDB-shaped API)

Subpath: @x12i/helpers/mongo. Exposes collection, ref, db, and client with the same mongo-like surface as @x12i/helpers/firebase-rtdb (insertOne, find, findOne, updateOne, query, per-doc get/set/update/delete, etc.). Uses MONGO_URI (or MONGODB_URI) from .env after loading via the same env loader as other helpers.

initMongoDb is async (MongoDB must connect over the network) unlike synchronous Firebase RTDB init:

const { initMongoDb, getMongoDb } = require("@x12i/helpers/mongo");

const mongo = await initMongoDb(); // reads MONGO_URI from .env
const users = mongo.collection("app/users");
const { insertedId } = await users.insertOne({ email: "[email protected]" });
await mongo.ref("app").remove(); // drops collections under path prefix (see docs)

Live tests: MONGO_LIVE_TESTS=1 — see test/mongo.live.test.js.

Amazon S3 (object I/O)

Subpath: @x12i/helpers/s3. Same method names as GCS: createS3Client, uploadObject, openReadStream, readObjectBuffer, listObjects, objectExists, deleteObject, getObjectMetadata, setObjectMetadata, plus matching error classes (S3NotFoundError, …). Configure S3_BUCKET, AWS_REGION, optional S3_ENDPOINT / S3_FORCE_PATH_STYLE for MinIO or LocalStack, and standard AWS credentials.

const { createS3Client } = require("@x12i/helpers/s3");

const s3 = createS3Client({ prefix: "my-app/uploads" });
await s3.uploadObject("k.txt", "hi", { contentType: "text/plain" });

Live tests: S3_LIVE_TESTS=1 — see test/s3.live.test.js.

Helper documentation

See helpers-docs/ for per-helper docs (what it is, why it exists, usage, and any .env keys it reads).

API

  • mapObject(source, mapping, opts)
  • createMapper(mapping, opts)
  • mapArray(sourceArray, mapping, opts)
  • deepGet(obj, path)
  • deepSet(obj, path, value)
  • requestToCurl(req)
  • curlToRequest(curlCommand)
  • buildUrl(baseUrl, pathOrUrl, query)
  • createBaseUrlClient(baseUrl, defaults)
  • defineContract(config)
  • createRegistry()
  • createBridge(config)
  • batchCall(bridge, paramsList, opts)
  • chainBridges(...bridges)
  • initFirebaseRtdb(options)
  • getFirebaseRtdb()
  • initFirebaseFirestore(options)
  • getFirebaseFirestore()

Subpath only (not re-exported from the root package):

  • @x12i/helpers/gcs: createGcsClient(options), GcsHelperError, GcsNotFoundError, GcsPermissionDeniedError, GcsFailedPreconditionError, GcsObjectTooLargeError
  • @x12i/helpers/mongo: initMongoDb(options), getMongoDb()
  • @x12i/helpers/s3: createS3Client(options), S3HelperError, S3NotFoundError, S3PermissionDeniedError, S3FailedPreconditionError, S3ObjectTooLargeError