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

@oppulence/core

v1.1.0

Published

Core utilities for Revenue Cloud packages

Readme

@oppulence/core

Core utilities for the Solomon AI platform providing essential functionality for logging, error handling, cryptography, async context management, and system operations.

Table of Contents

Installation

bun add @oppulence/core
# or
npm install @oppulence/core
# or
pnpm add @oppulence/core

Quick Start

import {
  // Error handling
  tryCatch,
  tryCatchSync,
  mapResult,
  isSuccess,

  // Logging
  Logger,
  createLogger,

  // Utilities
  debounce,
  throttle,
  memoize,
  sleep,
  deepMerge,

  // Crypto
  digestSHA256,
  hmacSHA256,
  generateRandomHex,

  // Shutdown
  shutdownManager,

  // Async context
  SafeAsyncLocalStorage,
} from "@oppulence/core";

Error Handling (Result Types)

Go-style error handling using Result tuples [Error | null, Data | null]. This pattern makes error handling explicit and prevents unhandled exceptions.

Basic Usage

import { tryCatch, tryCatchSync, Result } from "@oppulence/core";

// Async operations
const [error, data] = await tryCatch(fetch("/api/users"));
if (error) {
  console.error("Request failed:", error.message);
  return;
}
console.log("Users:", data);

// Sync operations
const [parseError, json] = tryCatchSync(() => JSON.parse(rawString));
if (parseError) {
  console.error("Invalid JSON");
  return;
}

With Timeout

import { tryCatchWithTimeout } from "@oppulence/core";

// Automatically fails if operation takes longer than 5 seconds
const [error, data] = await tryCatchWithTimeout(
  fetch("/api/slow-endpoint"),
  5000, // timeout in ms
  new Error("Request timed out") // optional custom error
);

With Abort Controller

import { tryCatchWithAbort } from "@oppulence/core";

const controller = new AbortController();

// Cancel after 10 seconds
setTimeout(() => controller.abort(), 10000);

const [error, data] = await tryCatchWithAbort(
  fetch("/api/data", { signal: controller.signal }),
  controller.signal
);

if (error?.name === "AbortError") {
  console.log("Request was cancelled");
}

Result Utilities

import {
  mapResult,
  flatMapResult,
  isSuccess,
  isFailure,
  unwrapResult,
  unwrapResultOr,
  combineResults,
} from "@oppulence/core";

// Transform success values
const userResult = await tryCatch(fetchUser(id));
const nameResult = mapResult(userResult, (user) => user.name);

// Chain Result-returning operations
const profileResult = flatMapResult(userResult, (user) =>
  tryCatchSync(() => parseProfile(user.rawProfile))
);

// Type guards
if (isSuccess(result)) {
  console.log("Data:", result[1]); // TypeScript knows result[1] is not null
}

// Extract values
const user = unwrapResult(userResult); // throws if error
const userOrDefault = unwrapResultOr(userResult, defaultUser); // returns default if error

// Combine multiple results
const results = await Promise.all([
  tryCatch(fetchUser(1)),
  tryCatch(fetchUser(2)),
  tryCatch(fetchUser(3)),
]);
const [error, users] = combineResults(results);
if (error) {
  console.error("At least one fetch failed");
} else {
  console.log("All users:", users); // users is User[]
}

Logging

Structured JSON logging with configurable levels, key masking, batching, and OpenTelemetry trace context support.

Basic Usage

import { Logger, createLogger } from "@oppulence/core";

// Create a logger
const logger = new Logger("my-service");
// or
const logger = createLogger("my-service");

// Log at different levels
logger.log("General message");
logger.info("Informational message", { userId: "123" });
logger.warn("Warning message", { threshold: 80 });
logger.error("Error occurred", { error: err });
logger.debug("Debug info", { query: sql });
logger.verbose("Verbose output", { trace: stack });

Key Masking

Automatically mask sensitive data in logs:

const logger = new Logger("auth", "info", ["password", "token", "apiKey"]);

logger.info("User login", {
  username: "john",
  password: "secret123",
  token: "abc123",
});
// Output: {"username":"john","password":"[FILTERED]","token":"[FILTERED]",...}

Child Loggers

Create loggers with inherited context:

const requestLogger = logger.child({
  requestId: "req-123",
  userId: "user-456",
});

// All logs include requestId and userId
requestLogger.info("Processing request");
requestLogger.info("Request complete", { duration: 150 });

OpenTelemetry Trace Context

import { trace } from "@opentelemetry/api";

const span = trace.getActiveSpan();
if (span) {
  const tracedLogger = logger.withTraceContext(span.spanContext());
  tracedLogger.info("Traced operation"); // Includes traceId, spanId
}

Log Batching (High-Throughput)

For high-throughput scenarios, batch logs to reduce I/O overhead:

const logger = new Logger("high-throughput");

logger.enableBatching({
  maxSize: 100, // Flush after 100 logs
  flushInterval: 1000, // Or flush every 1 second
});

// Logs are batched and written together
for (let i = 0; i < 1000; i++) {
  logger.info("Processing item", { index: i });
}

// Manually flush when needed
await logger.flush();

// Disable batching
logger.disableBatching();

Cryptography

Secure cryptographic utilities with module caching for optimal performance.

Hashing

import { digestSHA256, digestSHA512 } from "@oppulence/core";

const hash256 = await digestSHA256("Hello, World!");
// Returns 64-character hex string

const hash512 = await digestSHA512("Hello, World!");
// Returns 128-character hex string

HMAC Signing

import { hmacSHA256, hmacSHA512 } from "@oppulence/core";

// Sign data with a secret key
const signature = await hmacSHA256("secret-key", "data-to-sign");

// Verify webhook signatures
const expectedSig = await hmacSHA256(webhookSecret, requestBody);
if (expectedSig === receivedSignature) {
  // Valid signature
}

Random Generation

import {
  generateRandomBytes,
  generateRandomHex,
  generateId,
} from "@oppulence/core";

const bytes = await generateRandomBytes(32); // Uint8Array
const hex = await generateRandomHex(16); // 32-character hex string
const id = await generateId(12); // URL-safe random ID

Encoding Utilities

import {
  bufferToHex,
  hexToBuffer,
  base64Encode,
  base64Decode,
  base64UrlEncode,
  base64UrlDecode,
} from "@oppulence/core";

// Hex encoding
const hex = bufferToHex(buffer);
const buffer = hexToBuffer(hex);

// Base64 encoding
const encoded = base64Encode("Hello");
const decoded = base64Decode(encoded);

// URL-safe Base64 (no padding, URL-safe chars)
const urlSafe = base64UrlEncode("Hello");
const original = base64UrlDecode(urlSafe);

Secure Comparison

import { constantTimeCompare } from "@oppulence/core";

// Timing-safe string comparison (prevents timing attacks)
if (constantTimeCompare(providedToken, storedToken)) {
  // Tokens match
}

Async Context (AsyncLocalStorage)

Safe wrapper around Node.js AsyncLocalStorage for request-scoped context.

Basic Usage

import { SafeAsyncLocalStorage, createAsyncLocalStorage } from "@oppulence/core";

interface RequestContext {
  requestId: string;
  userId?: string;
  startTime: number;
}

const requestContext = new SafeAsyncLocalStorage<RequestContext>();
// or
const requestContext = createAsyncLocalStorage<RequestContext>();

// Set context for a scope
requestContext.runWith(
  { requestId: "req-123", startTime: Date.now() },
  async () => {
    // Context is available in all async operations
    await handleRequest();
  }
);

// Access context anywhere in the call chain
function logMessage(msg: string) {
  const ctx = requestContext.getStore();
  if (ctx) {
    console.log(`[${ctx.requestId}] ${msg}`);
  }
}

Safe Access Methods

// Get with default value
const ctx = requestContext.getStoreOrDefault({
  requestId: "unknown",
  startTime: 0,
});

// Get or throw (for required context)
try {
  const ctx = requestContext.getStoreOrThrow("Context required");
} catch (e) {
  // Handle missing context
}

// Check if context exists
if (requestContext.hasStore()) {
  const ctx = requestContext.getStore()!;
}

Update Context

requestContext.runWith(
  { requestId: "req-123", startTime: Date.now() },
  async () => {
    // Later, after authentication
    requestContext.update({ userId: "user-456" });

    // Context now has both requestId and userId
    const ctx = requestContext.getStore();
    // { requestId: 'req-123', startTime: ..., userId: 'user-456' }
  }
);

Middleware Helper

// Create middleware for Express/Koa-like frameworks
const withContext = requestContext.middleware((req: Request) => ({
  requestId: (req.headers["x-request-id"] as string) || generateId(),
  startTime: Date.now(),
}));

// Wrap handlers
app.get(
  "/api/users",
  withContext(async (req, res) => {
    const ctx = requestContext.getStore();
    // Context is automatically set
  })
);

Exit Context

requestContext.runWith({ requestId: "req-123" }, () => {
  console.log(requestContext.getStore()); // { requestId: 'req-123' }

  // Run code outside the context
  requestContext.exit(() => {
    console.log(requestContext.getStore()); // undefined
  });

  console.log(requestContext.getStore()); // { requestId: 'req-123' }
});

Shutdown Management

Graceful shutdown handling with priority ordering and timeouts.

Basic Usage

import { shutdownManager, ShutdownManager } from "@oppulence/core";

// Register cleanup handlers
shutdownManager.register("database", async (signal) => {
  console.log(`Closing database (${signal})`);
  await database.close();
});

shutdownManager.register("cache", async () => {
  await cache.flush();
});

// Handlers run automatically on SIGTERM/SIGINT

Priority and Timeout

// Lower priority runs first
shutdownManager.register(
  "critical-cleanup",
  async () => {
    await flushLogs();
  },
  {
    priority: 0, // Runs first
    timeout: 5000, // 5 second timeout
  }
);

shutdownManager.register(
  "database",
  async () => {
    await database.close();
  },
  {
    priority: 10, // Runs after priority 0
    timeout: 10000, // 10 second timeout
  }
);

shutdownManager.register(
  "optional-cleanup",
  async () => {
    await sendMetrics();
  },
  {
    priority: 100, // Runs last
    timeout: 2000,
    signals: ["SIGTERM"], // Only on SIGTERM, not SIGINT
  }
);

Manual Shutdown

// Trigger shutdown manually
await shutdownManager.shutdown("SIGTERM");

// With options
await shutdownManager.shutdown("SIGTERM", {
  timeout: 30000, // Global timeout
  skipExit: true, // Don't call process.exit (useful for testing)
});

Utility Functions

Debounce

Collapse multiple calls into one:

import { debounce } from "@oppulence/core";

const debouncedSave = debounce(saveDocument, 1000, {
  leading: false, // Don't execute on leading edge
  trailing: true, // Execute on trailing edge (default)
  maxWait: 5000, // Maximum time to wait
});

// Multiple rapid calls
debouncedSave(doc);
debouncedSave(doc);
debouncedSave(doc); // Only this executes after 1 second

// Control methods
debouncedSave.cancel(); // Cancel pending execution
debouncedSave.flush(); // Execute immediately
debouncedSave.pending(); // Check if execution is pending

Throttle

Rate-limit function calls:

import { throttle } from "@oppulence/core";

const throttledScroll = throttle(handleScroll, 100, {
  leading: true, // Execute on leading edge
  trailing: true, // Execute on trailing edge
});

window.addEventListener("scroll", throttledScroll);
// Executes at most once per 100ms

Memoize

Cache function results:

import { memoize, memoizeAsync } from "@oppulence/core";

// Sync memoization
const expensiveCalc = memoize(
  (n: number) => {
    // Complex calculation
    return fibonacci(n);
  },
  {
    maxSize: 100, // LRU cache size
    ttl: 60000, // Cache TTL in ms
  }
);

// Async memoization
const fetchUser = memoizeAsync(
  async (id: string) => {
    return await api.getUser(id);
  },
  {
    maxSize: 50,
    ttl: 300000, // 5 minutes
    resolver: (id) => id, // Custom cache key
  }
);

// Methods
expensiveCalc.clear(); // Clear cache

Sleep

import { sleep, sleepWithSignal, delay } from "@oppulence/core";

// Simple delay
await sleep(1000); // Wait 1 second

// Cancellable delay
const controller = new AbortController();
setTimeout(() => controller.abort(), 500);

try {
  await sleepWithSignal(1000, controller.signal);
} catch (e) {
  console.log("Sleep was cancelled");
}

// Delay with cleanup
const { promise, cancel } = delay(1000);
setTimeout(cancel, 500); // Cancel after 500ms
try {
  await promise;
} catch (e) {
  console.log("Delay was cancelled");
}

Retry

import { retry } from "@oppulence/core";

const result = await retry(
  async () => {
    const response = await fetch("/api/data");
    if (!response.ok) throw new Error("Request failed");
    return response.json();
  },
  {
    maxAttempts: 3,
    initialDelay: 1000,
    maxDelay: 10000,
    backoffFactor: 2, // Exponential backoff
    shouldRetry: (error, attempt) => {
      // Custom retry logic
      return attempt < 3 && error.message !== "Not Found";
    },
  }
);

Deep Merge

import { deepMerge, deepMergeWithOptions, deepFreeze } from "@oppulence/core";

const defaults = {
  server: { host: "localhost", port: 3000 },
  logging: { level: "info" },
};

const overrides = {
  server: { port: 8080 },
  logging: { format: "json" },
};

const config = deepMerge(defaults, overrides);
// {
//   server: { host: 'localhost', port: 8080 },
//   logging: { level: 'info', format: 'json' }
// }

// With options
const merged = deepMergeWithOptions(defaults, overrides, {
  arrayMerge: "replace", // 'replace' | 'concat' | 'unique'
  clone: true, // Clone objects instead of mutating
});

// Deep freeze for immutability
const frozen = deepFreeze(config);
frozen.server.port = 9000; // TypeError in strict mode

Deep Get/Set

import { getDeep, setDeep } from "@oppulence/core";

const obj = { user: { profile: { name: "John" } } };

// Get nested value
const name = getDeep(obj, "user.profile.name"); // 'John'
const missing = getDeep(obj, "user.profile.age", 0); // 0 (default)

// Set nested value (returns new object)
const updated = setDeep(obj, "user.profile.age", 30);
// { user: { profile: { name: 'John', age: 30 } } }

Pick and Omit

import { pick, pickBy, omit } from "@oppulence/core";

const user = { id: 1, name: "John", password: "secret", role: "admin" };

// Pick specific keys
const public = pick(user, ["id", "name"]);
// { id: 1, name: 'John' }

// Pick by predicate
const strings = pickBy(user, (value) => typeof value === "string");
// { name: 'John', password: 'secret', role: 'admin' }

// Omit keys
const safe = omit(user, ["password"]);
// { id: 1, name: 'John', role: 'admin' }

Singleton Pattern

import { singleton } from "@oppulence/core";

// Create or retrieve singleton instance
const cache = singleton("app-cache", () => new Map());
const sameCache = singleton("app-cache", () => new Map());

console.log(cache === sameCache); // true

Type Utilities

Branded Types

Prevent mixing up values with the same underlying type:

import { Brand, brand, UserId, TeamId, Email } from '@oppulence/core';

// Pre-defined branded types
const userId: UserId = brand<UserId>('user_123');
const teamId: TeamId = brand<TeamId>('team_456');
const email: Email = brand<Email>('[email protected]');

// Custom branded types
type OrderId = Brand<string, 'OrderId'>;
type SKU = Brand<string, 'SKU'>;

function getOrder(id: OrderId): Order { ... }

const orderId = brand<OrderId>('order_789');
getOrder(orderId); // OK
getOrder(userId);  // Type error!

Deep Utility Types

import {
  DeepPartial,
  DeepReadonly,
  DeepRequired,
  DeepMutable,
} from "@oppulence/core";

interface Config {
  server: {
    host: string;
    port: number;
    ssl: {
      enabled: boolean;
      cert: string;
    };
  };
}

// All nested properties optional
type PartialConfig = DeepPartial<Config>;

// All nested properties readonly
type ImmutableConfig = DeepReadonly<Config>;

// All nested properties required
type FullConfig = DeepRequired<Config>;

// Remove readonly from all nested properties
type MutableConfig = DeepMutable<ImmutableConfig>;

Other Utility Types

import {
  RequireKeys,
  PartialKeys,
  Prettify,
  Awaitable,
  MaybeArray,
  AsyncReturnType,
  KeysOfType,
  PickByType,
  OmitByType,
  JsonValue,
  Jsonify,
} from "@oppulence/core";

// Make specific keys required
type UserCreate = RequireKeys<User, "email" | "name">;

// Make specific keys optional
type UserUpdate = PartialKeys<User, "name" | "avatar">;

// Expand complex types for readability
type Expanded = Prettify<SomeComplexIntersection>;

// Value or Promise of value
type Handler = (req: Request) => Awaitable<Response>;

// Single or array
type Input = MaybeArray<string>; // string | string[]

// Get return type of async function
type UserData = AsyncReturnType<typeof fetchUser>;

// Get keys by value type
type StringKeys = KeysOfType<User, string>; // 'name' | 'email'

// JSON serialization type
type ApiResponse = Jsonify<InternalUser>; // Converts Date to string, removes functions

Schemas

Zod schemas for common patterns:

import {
  RetryOptionsSchema,
  RateLimitOptionsSchema,
  // ... other schemas
} from "@oppulence/core";

// Validate configuration
const config = RetryOptionsSchema.parse({
  maxAttempts: 3,
  initialDelay: 1000,
});

API Reference

Error Handling

| Function | Description | | ------------------------------------------------ | ------------------------------------ | | tryCatch<T, E>(promise) | Wrap async operation in Result tuple | | tryCatchSync<T, E>(fn) | Wrap sync operation in Result tuple | | tryCatchWithTimeout<T, E>(promise, ms, error?) | With timeout | | tryCatchWithAbort<T, E>(promise, signal) | With abort signal | | mapResult<T, U, E>(result, fn) | Transform success value | | flatMapResult<T, U, E>(result, fn) | Chain Result operations | | isSuccess<T, E>(result) | Type guard for success | | isFailure<T, E>(result) | Type guard for failure | | unwrapResult<T, E>(result) | Extract value or throw | | unwrapResultOr<T, E>(result, default) | Extract value or default | | combineResults<T, E>(results) | Combine array of Results |

Logging

| Method | Description | | ------------------------------------------------------ | ------------------- | | new Logger(name, level?, maskedKeys?, replacer?) | Create logger | | logger.log/info/warn/error/debug/verbose(msg, data?) | Log at level | | logger.child(context) | Create child logger | | logger.withTraceContext(spanContext) | Add trace context | | logger.enableBatching(options) | Enable log batching | | logger.disableBatching() | Disable batching | | logger.flush() | Flush batched logs |

Cryptography

| Function | Description | | ------------------------------- | ------------------- | | digestSHA256(data) | SHA-256 hash | | digestSHA512(data) | SHA-512 hash | | hmacSHA256(key, data) | HMAC-SHA256 | | hmacSHA512(key, data) | HMAC-SHA512 | | generateRandomBytes(length) | Random bytes | | generateRandomHex(length) | Random hex string | | generateId(length?) | Random URL-safe ID | | constantTimeCompare(a, b) | Timing-safe compare | | base64Encode/Decode(data) | Base64 encoding | | base64UrlEncode/Decode(data) | URL-safe Base64 | | bufferToHex/hexToBuffer(data) | Hex encoding |

Utilities

| Function | Description | | ------------------------------ | ---------------------- | | debounce(fn, wait, options?) | Debounce function | | throttle(fn, wait, options?) | Throttle function | | memoize(fn, options?) | Memoize sync function | | memoizeAsync(fn, options?) | Memoize async function | | sleep(ms) | Promise-based delay | | sleepWithSignal(ms, signal) | Cancellable delay | | retry(fn, options?) | Retry with backoff | | delay(ms) | Delay with cancel | | deepMerge(...objects) | Deep merge objects | | deepFreeze(obj) | Deep freeze object | | getDeep(obj, path, default?) | Get nested value | | setDeep(obj, path, value) | Set nested value | | pick(obj, keys) | Pick object keys | | pickBy(obj, predicate) | Pick by predicate | | omit(obj, keys) | Omit object keys | | singleton(key, factory) | Get/create singleton |

AsyncLocalStorage

| Method | Description | | ---------------------------- | -------------------- | | runWith(context, fn) | Run with context | | run(context, fn) | Alias for runWith | | enterWith(context) | Set context directly | | exit(fn) | Run outside context | | getStore() | Get current context | | getStoreOrDefault(default) | Get or default | | getStoreOrThrow(message?) | Get or throw | | hasStore() | Check if context set | | update(partial) | Update context | | middleware(getContext) | Create middleware | | disable() | Disable storage |

Shutdown Manager

| Method | Description | | ----------------------------------- | ---------------- | | register(name, handler, options?) | Register handler | | shutdown(signal, options?) | Trigger shutdown |

Environment Variables

| Variable | Description | | ------------------- | ------------------ | | TRIGGER_LOG_LEVEL | Override log level | | NODE_ENV | Environment mode |

License

ISC