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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@nth-erik/stoic

v1.0.0

Published

Stoic is a simple JavaScript library for instantiating immutable reference type data for use as enumerables and schemata.

Readme

Stoic - Immutable pseudo-primitive structures

A lightweight utility for creating deeply immutable, prototype-free data structures. Useful for schema definitions, safe config data, or readonly runtime state.

Notice of LLM (AI) support

:robot: Contains supervised vibecode from ChatGPT-4o.

Installation

npm i @nth-erik/stoic

Usage

Example:

const { Stoic } = await import('@nth-erik/stoic');

const stoicObject = Stoic.create({
  a: 'Hello',
  b: ['world!'],
});

stoicObject.a = 'Goodbye';
stoicObject.b[0] = 'cruel world...';
console.log(Object.values(stoicObject).flat().join(', ')); // Hello, world!

API

Stoic

The Stoic namespace provides core utilities for freezing data into deeply immutable, read-only structures.

Stoic.create(source)

Creates a deeply immutable, prototype-free clone of any supported value.

Parameters:

  • source - The value to sanitize and wrap. It can be of any supported type.

Returns:

  • A deeply frozen Stoic structure or primitive. The function ensures that the returned value is:
    • Primitives are returned as-is.
    • Arrays are wrapped as StoicArray instances.
    • Plain objects are wrapped as StoicObject instances.
    • Errors are cloned into StoicError instances.
    • Known immutable types (e.g., Date, RegExp) are returned as their primitive representation (e.g., number, string).

Throws:

  • TypeError if the input contains unsupported or unsafe types (e.g., Promise, WeakMap, Function).

Circular References:

  • Circular references are replaced with undefined, and a warning is logged that includes the original and current paths.

Example:

const frozen = Stoic.create({
  name: 'Alice',
  tags: ['admin'],
  created: new Date(),
});

frozen.name = 'Bob'; // ❌ TypeError

Stoic.delegateStoicMethods(options)

Defines non-mutating methods on a custom prototype by delegating to a built-in JavaScript prototype (e.g., Array.prototype or Object.prototype).

Parameters:

  • options.target (Object) - The prototype to define methods on.
  • options.source (Object) - The built-in prototype to delegate method calls to.
  • options.mapping (Object.<string, false|function>) - Map of method names to wrapping strategies.
    • If the value is false, the result is returned as-is.
    • If the value is a function, the result is passed to that function and its return value is used.

Returns:

  • A modified prototype with the delegated and possibly wrapped methods.

Example:

Stoic.delegateStoicMethods({
  target: StoicArray.prototype,
  source: Array.prototype,
  mapping: {
    map: (result) => new StoicArray(result),
    includes: false,
  },
});

StoicError(error)

Creates a deeply immutable, prototype-free error structure. This is useful for safe logging or serialization without exposing prototype behavior.

Parameters:

  • error (Error): A native Error instance to wrap.

Returns:

  • A deeply frozen StoicError that is stripped of prototype. The structure retains name, message, stack, and optionally cause (if available).

Throws:

  • TypeError: If the input is not an Error instance.
const err = new Error('Something went wrong');
const frozenErr = new StoicError(err);
console.log(frozenErr.stack); // Logs stack trace

StoicObject(source)

Creates a deeply immutable plain object with no prototype. All nested objects and arrays are recursively wrapped and frozen, ensuring the structure cannot be modified.

Parameters:

  • source (Object): The plain object to convert into a deeply frozen structure.

Returns:

  • A deeply frozen StoicObject.

Throws:

  • TypeError: If the input is not a plain object.
const config = new StoicObject({ debug: true });
config.debug = false; // ❌ TypeError: Cannot assign to read only property 'debug'

StoicArray(source)

Creates a deeply immutable array-like structure with no prototype. All nested values are recursively frozen. Includes most read-only array methods (e.g., map, slice, find).

Parameters:

  • source (Array): The array to convert into a deeply frozen structure.

Returns:

  • A deeply frozen StoicArray.

Throws:

  • TypeError: If the input is not an array.
const frozenArr = new StoicArray(['a', 'b']);
frozenArr[0] = 'x'; // ❌ TypeError: Cannot assign to read only property '0'

FAQ

  • Q: Are you one of these braindead evangelists who thinks we should just random-roll our functions?

  • A: No, but I'm also not a masochist. Fortunately the AI is a tireless coder an intelligent developer can brainstorm with, addressing potential points of failure, and reason about cryptic implementation choices. This way I can delegate chores, and focus on refining and improving the initial solution with a mix of follow-up questions and optimizations from both ends.

  • Q: Is this it? Three object types and a namespace?

  • A: Yeah, it's not even minimized, so anyone can take a look and tell me why it sucks.

  • Q: Why are Stoic, StoicError, StoicObject and StoicArray in a single module?

  • A: Because they are deeply interdependent to ensure deeply immutable structures. Separating them would create a dependency loop.