Open-source project
stampit-org/stampit avatar
stampit-org/stampit

stampit: the size script prints a number and asserts nothing

OOP is better with stamps: Composable object factories.

3,004 stars102 forksTypeScriptMIT

At a glance

What is it?
Stampit is a small composable object factory module with no runtime dependencies, and its whole library is one source file. The build configuration is stricter than the readme suggests in most places and looser in exactly one: the script that measures the bundle size reports it without failing when the number grows.
Who is it for?
Stampit is a reasonable choice if you want composition instead of class hierarchies and you are willing to hold the stamp specification in your head, because the API is small, the published surface is three files and there is nothing to install alongside it. It is a poor choice if you are still on CommonJS and reading release titles rather than manifests, since the fifth major line moved twice in a matter of months.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 87 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The 5.0.1 release says CommonJS came back and the manifest has no require branch

The three most recent releases have titles that read like a story. v5.0.0 is titled ESM support, published 2025-10-05. Nine days later v5.0.1 is titled Return the CJS support. Then v5.1.0, on 2026-07-02, is titled TypeScript rewrite, and the top level of the tree now holds a single stampit.ts. The manifest in that tree disagrees with the middle title. The package declares type module, and its exports map has exactly two keys under the main entry, types pointing at the declaration file and default pointing at the compiled JavaScript. There is no require condition and no nested CommonJS branch, and the published files list contains the TypeScript source, the compiled JavaScript and the declaration file, with no separate CommonJS build among them. So either the CommonJS return was reverted, or it lives somewhere the manifest does not describe. Either way, reading the release title is not a reliable way to know whether require works.

The size script prints the gzip number and asserts nothing

The readme advertises a 1.3KB gzipped, or 4.8K minified, module, and the manifest contains the script that produces that figure. It runs the minifier over the compiled file with a long list of compression options including unsafe and pure_getters, reserves the identifiers stampit and Stamp, keeps those function names, writes a minified file, and then pipes it through a gzip size tool with the raw flag and the include-original flag. Here is the whole command:

Two things follow. The script minifies the compiled file into a temporary name, measures it, echoes the gzip result, and then deletes the minified file, and there is no comparison against a threshold anywhere in it, so a size regression produces a larger number in the log and a passing run. And the figure the readme quotes comes from a configuration that turns on unsafe and pure_getters compressions, which are the settings that let a minifier drop code it cannot prove safe.

npm t builds, typechecks, tests and then measures the bundle

The Development section documents two commands and the manifest defines nine scripts. The documented ones are npm t for unit tests and npm run test:benchmark for benchmarks. The one that matters is what npm t actually does:

So the unit test alias is a four stage pipeline. It compiles with the build configuration, runs a separate typecheck over the other configuration, executes the test files with the platform's own test runner, and finishes by measuring the bundle. There is no separate test script, which means there is no way to run the tests without also building and measuring them. The benchmark script is the opposite: it runs the test runner over the benchmark directory with no build step, so it uses whatever compiled output happens to be present. The continuous integration script chains the three of them in the order test, lint, benchmark.

The coverage script calls open, which is a macOS command

One script in the manifest will not run everywhere the library does. The coverage script is a single line that runs the coverage tool with an HTML reporter over the test command and then calls open on the generated report path. There is no cross-platform opener in the dependency list, so on Linux and Windows this script reaches the final command and fails, after having done the expensive part. That is a small thing on its own, and it is worth noticing mainly because it sits alongside two scripts that are carefully portable. The size script avoids any viewer by deleting its own output, and the test pipeline calls the platform test runner directly. The lint script is equally deliberate, using oxlint rather than the more common linter and skipping two patterns, the generated declaration file and the compiled JavaScript, so linting never reads the build output.

The API section is one line and two of the three examples are cut off

The page is 237 words and the API section is one sentence: see the website. There is no parameter list, no method table and no type reference on the page itself, so the documentation is entirely external. What the page does carry is three code examples and two of them are incomplete. The first builds a Character stamp with name and health, composes a Fighter that adds stamina and a fight method, and begins a Mage with mana before the listing stops mid-keyword on the methods key. The second is the What's the Point section, which motivates the library by asking how to inherit privileged methods with private data, then builds an Availability stamp that keeps its flag in a closure variable and exposes open, close and an isOpen method, before starting a Membership stamp with a members property and an add method and stopping mid-object. The third is not present at all.

The status list keeps four majors installable and one tag link loses its prefix

A Status section keeps every major line reachable, which is unusual and useful:

code
npm i stampit@1
npm i stampit@2
npm i stampit@3
npm i stampit@4
npm i stampit

Alongside each line there is a specification compatibility note, and those notes have not moved in two majors. Version 3 is compatible with the stamp specification up to and including 1.4. Versions 4 and 5 are both compatible with version 1.5 of the same specification, even though 5 changed the module format and was then rewritten in TypeScript. One detail is inconsistent: the breaking changes link for version 2 points at a release tag written without the v prefix, while versions 3, 4 and 5 point at tags written with it. So the first link in the list is also the only one that will not resolve by copying the pattern from its neighbours.

One source file, no runtime dependencies and a TypeScript 6 toolchain

The repository is nine entries and the library is one of them. There is a stampit.ts at the top level, a test directory, two TypeScript configurations named build and plain, an editor config, a licence file written as LICENSE.md rather than LICENSE, and the two package files. There is no dependencies key in the manifest at all, which is why a library whose headline is its weight in kilobytes can make that claim without arithmetic. The toolchain that produces it is more recent than the library. The dev dependencies include typescript on a version 6 range, oxlint for linting, c8 for coverage, uglify-js for the size measurement, a gzip size command line tool, prettier for formatting, a benchmark harness, and one entry whose purpose the readme never mentions, a package named check-compose. The two authors named are Eric Elliott and Vasyl Boroviak.

Editorial conclusion

Stampit is a reasonable choice if you want composition instead of class hierarchies and you are willing to hold the stamp specification in your head, because the API is small, the published surface is three files and there is nothing to install alongside it. It is a poor choice if you are still on CommonJS and reading release titles rather than manifests, since the fifth major line moved twice in a matter of months. Before you pin a version, check the exports map of the exact release you are installing rather than the release notes, and if the size claim matters to you, wire a threshold onto it yourself, because the project's own measurement step prints the figure and moves on.

Frequently asked questions

what is stampit

It is a small JavaScript and TypeScript module for creating objects from reusable, composable behaviours, described as supporting three kinds of prototypal inheritance: delegation, concatenation and functional. Stamps are standardised composable factory functions, and stampit is an implementation of that specification. The readme quotes 1.3KB gzipped, or 4.8K minified.

how to use stampit

Import the default export and call it with a descriptor holding props, init and methods, then compose the result to inherit behaviour. The readme's worked example defines a Character with name and health, composes a Fighter that adds stamina and a fight method, and composes a Mage. The API section of the readme is one line pointing at stampit.js.org, so the full reference is external.

How do I install a specific major version of stampit?

The Status section lists npm i stampit@1 through npm i stampit@4, and plain npm i stampit for version 5, which is the current major. Each older line also has a breaking changes link on the releases page, though the version 2 link is written without the v prefix the other three use.

Does stampit 5 support CommonJS?

The release list says v5.0.0 added ESM support and v5.0.1, nine days later, returned CommonJS support. The manifest in the repository declares type module with an exports map containing only types and default, and the published files list holds the TypeScript source, the compiled JavaScript and the declaration file with no separate CommonJS build. Check the exports map of the exact version you install.

How do I run the stampit tests?

npm t, which is what the readme documents for unit tests. That alias builds with one TypeScript configuration, typechecks with the other, runs the test files with the platform test runner, and then runs the size measurement. Benchmarks are separate, npm run test:benchmark, and that script does not build first.

Which version of the stamp specification does stampit target?

Version 3 is listed as compatible with the stamp specification up to and including 1.4. Versions 4 and 5 are both listed as compatible with version 1.5, so the specification compatibility has not moved across the two most recent major changes, which were a module format change and a TypeScript rewrite.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. stampit-org/stampit on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stampit-org-stampit.svg)](https://hysenlabs.com/projects/stampit-org-stampit)