
Security News
Node.js Considers Public Workflow for Security Reports Amid AI-Driven Surge
Node.js is debating whether AI-driven security report volume warrants moving more vulnerability reports into public workflows.
Lightweight utility to make objects and arrays immutable with shallow and deep freeze
Lightweight, zero-dependency TypeScript utility for making objects and arrays deeply immutable. Shallow and recursive freeze with full type safety.
npm install constancy
# or
yarn add constancy
# or
pnpm add constancy
Requires Node.js >= 14.
import constancy, { deepFreeze } from 'constancy';
// Shallow freeze — top-level properties only
const config = constancy({ host: 'localhost', port: 3000 });
config.port = 8080; // Ignored (TypeError in strict mode)
// Deep freeze — all nested properties recursively
const state = deepFreeze({
user: { name: 'Alice', roles: ['admin'] },
settings: { theme: 'dark' },
});
state.user.name = 'Bob'; // Ignored
state.user.roles.push('user'); // Ignored
constancy<T>(val: T)Shallow-freezes an object or function using Object.freeze(). Primitives are returned unchanged.
Returns: Readonly<T> for objects/functions, T for primitives.
import constancy from 'constancy';
constancy({ a: 1 }); // Readonly<{ a: number }>
constancy([1, 2, 3]); // readonly number[]
constancy(() => 'hello'); // Frozen function (still callable)
constancy('text'); // 'text' — unchanged
constancy(42); // 42 — unchanged
constancy(null); // null — unchanged
Nested objects are NOT frozen:
const obj = constancy({ user: { name: 'Alice' } });
obj.user.name = 'Bob'; // Works — nested is not frozen
obj.user = {}; // Ignored — top-level is frozen
deepFreeze<T>(val: T)Recursively freezes a value and all reachable nested objects. Handles:
Reflect.ownKeys())get/set) — skipped to avoid unintended invocationReturns: DeepReadonly<T> for objects, T for primitives.
import { deepFreeze } from 'constancy';
const obj = deepFreeze({
nested: { count: 0 },
tags: ['a', 'b'],
});
obj.nested.count = 1; // Ignored
obj.tags.push('c'); // Ignored
// Circular references are safe
const node: any = { value: 1 };
node.self = node;
deepFreeze(node); // No infinite loop
DeepReadonly<T>Recursively marks all properties as readonly. Handles objects, arrays, Maps, and Sets.
import type { DeepReadonly } from 'constancy';
type Config = DeepReadonly<{
db: { host: string; port: number };
tags: string[];
}>;
// Config.db.host is readonly, Config.tags is ReadonlyArray<string>
FreezableUnion type of values that can be frozen: object | Function.
import type { Freezable } from 'constancy';
function freeze(val: Freezable) {
return Object.freeze(val);
}
Named and default imports are both supported:
// Default import
import constancy from 'constancy';
// Named imports
import { constancy, deepFreeze } from 'constancy';
import type { DeepReadonly, Freezable } from 'constancy';
CommonJS:
const { constancy, deepFreeze } = require('constancy');
| v1 | v2 |
|---|---|
| Node.js >= 10 | Node.js >= 14 required |
CommonJS-first (index.js) | ESM-first ("type": "module") |
Object.freeze polyfill included | Removed — native in all supported environments |
import constancy from 'constancy' | Same — default import still works |
No deepFreeze | deepFreeze() added |
No DeepReadonly<T> | Type exported |
v1 root entry (index.js, index.d.ts) is removed. Imports via the package name continue to work through the exports field:
// Still works in v2
import constancy from 'constancy';
import { constancy, deepFreeze } from 'constancy';
Direct path imports (from 'constancy/dist/...') are not supported.
# Build ESM + CJS bundles
npm run build
# Run tests
npm test
# Watch mode
npm run test:watch
# Coverage report
npm run test:coverage
# Type check
npm run typecheck
src/
├── index.ts — barrel exports
├── constancy.ts — shallow freeze
├── deep-freeze.ts — recursive deep freeze
├── types.ts — DeepReadonly<T>, Freezable
└── utils.ts — isFreezable(), getOwnKeys()
tests/
├── constancy.test.ts — 19 tests
└── deep-freeze.test.ts — 11 tests
dist/ — built output (ESM + CJS + .d.ts)
Readonly<T> and DeepReadonly<T> inferred automaticallyMIT — DungGramer
FAQs
Zero-dependency immutability toolkit: freeze, view, snapshot, vault, and integrity verification
The npm package constancy receives a total of 25 weekly downloads. As such, constancy popularity was classified as not popular.
We found that constancy demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Node.js is debating whether AI-driven security report volume warrants moving more vulnerability reports into public workflows.

Security News
PolinRider expands across npm, Packagist, Go modules, and Chrome extensions, using hidden loaders to target developer environments.

Security News
Open source attacks are accelerating as AI coding agents pull in dependencies faster, with less human review.