-
Notifications
You must be signed in to change notification settings - Fork 2
utils
Core cross-runtime TypeScript building blocks — a typed Options + Events base class, BaseError, Singleton, and helpers for config/env, memoize, throttle, IP/subnet, and free-port lookup.
utils is the dependency-free foundation the rest of TundraLibs builds
on: BaseError is the root of every package's error hierarchy,
Options/Events is the base class most config-bearing classes
extend, and Singleton backs classes that must have exactly one
instance. Around that core sit small, independent helpers — decorators
(Once/Memoize/Throttle), config/env loading, IP/subnet checks,
syslog parsing, string templating — that have no dependency on each
other or on the core classes; reach for only the ones you need.
Once, Memoize, and Throttle are TC39 standard decorators (no
experimentalDecorators). Memoize and Throttle work on both
methods and getters; Once is method-only — decorating a getter with
@Once is a compile-time type error, not a supported (if degraded)
case. Singleton is also available as its own subpath import
(@tundralibs/utils/Singleton) for consumers who only need it.
See examples/connection-pool/ for a
small runnable app that composes Options, Events, BaseError, and
Singleton — the four core pieces — into one class.
Most of the surface — BaseError, Options/Events, Singleton,
Once/Memoize/Throttle, variableReplacer, IP/subnet helpers —
is pure and runs unchanged on Workers and in the browser; importing
the barrel never throws there. Two exceptions need a real OS to mean
anything: getFreePort() binds a real socket to probe availability,
and Config/loadConfig() reads real files from disk — neither
concept exists in a Worker or a browser, so don't reach for them
there. Every module has its own subpath — @tundralibs/utils/syslog,
@tundralibs/utils/envArgs, @tundralibs/utils/BaseError, one per file —
so the barrel is a convenience, never the only way in. Prefer a subpath
when bundle size matters: the barrel is one module graph, so importing it
for a single symbol pulls the whole package in. Measured with
deno info, @tundralibs/utils/syslog is a 2-module graph where the
barrel is 158.
Deno:
deno add @tundralibs/utilsBun:
bunx jsr add @tundralibs/utilsNode.js:
npx jsr add @tundralibs/utils| Utility | Description | Documentation |
|---|---|---|
| BaseError | Enhanced error class with context, chaining, and code snippets | Docs |
| Config | Multi-format configuration loader with environment variable support | Docs |
| envArgs | Environment variable and .env file loader with Docker secrets support | Docs |
| Events | Type-safe event system with async support | Docs |
| getFreePort | Find available TCP ports with configurable range and exclusions | Docs |
| ipUtils | IPv4/IPv6 validation, conversion, and range checking utilities | Docs |
| isInSubnet | Check if IP address is within a CIDR subnet range | Docs |
| isPublicIP | Detect if IP address is publicly routable | Docs |
| isSubnet | Validate CIDR subnet notation format | Docs |
| memoize | Function and method memoization with TTL and async support | Docs |
| once | Function execution control for single-call enforcement | Docs |
| Options | Abstract base class for options and event handling | Docs |
| privateObject | Private data encapsulation utility | Docs |
| Singleton | Singleton pattern decorator | Docs |
| syslog | RFC 3164 and RFC 5424 syslog parser and generator | Docs |
| templatize | Type-safe template string parser | Docs |
| throttle | Function throttling for rate-limiting execution | Docs |
| Types | Advanced TypeScript utility types for type manipulation | Docs |
| variableReplacer | Template placeholder replacement with dot notation support | Docs |
import { getFreePort, isInSubnet, isPublicIP } from '@tundralibs/utils';
// Find available port for dev server
const port = await getFreePort({ min: 3000, max: 4000 });
// Check if IP is in subnet
if (isInSubnet('192.168.1.10', '192.168.0.0/16')) {
console.log('IP is in private network');
}
// Detect public vs private IP
if (isPublicIP('8.8.8.8')) {
console.log('Public IP detected');
}import { loadConfig } from '@tundralibs/utils';
const config = await loadConfig({ path: './config' });
const dbHost = config.get<string>('database.host');import { BaseError } from '@tundralibs/utils';
class ValidationError extends BaseError<{ field: string }> {
// Enhanced error with context
}
throw new ValidationError('Invalid ${field}', { field: 'email' });import { memoize, throttle } from '@tundralibs/utils';
const factorial = (n: number): number => (n <= 1 ? 1 : n * factorial(n - 1));
const updateUI = () => console.log('viewport changed');
const expensiveCalc = memoize((n: number) => factorial(n), 5000);
const handleScroll = throttle(() => updateUI(), 100);import { once, Singleton } from '@tundralibs/utils';
@Singleton
class DatabaseConnection {
// Ensures single instance
}
const initialize = once(() => {
// Runs only once
});MIT © TundraLibs