lifecycleion
v0.1.0
Published
A collection of foundational TypeScript utilities for managing application lifecycle, logging, retries, events, and common programming patterns
Maintainers
Readme
Lifecycleion v0.1.0
A collection of foundational TypeScript utilities for managing application lifecycle, logging, retries, events, and common programming patterns.
⚠️ Pre-1.0.0: Lifecycleion is maturing and usable, but still pre-1.0. The core APIs are stabilizing yet may still change before 1.0.0. Pin a version and review release notes when upgrading.
Why Lifecycleion?
Lifecycleion provides TypeScript utilities for application lifecycle orchestration, logging, retries, events, HTTP requests, and common programming patterns.
Key Features
- 🌐 HTTP Client - Fluent request builder with Fetch, Node.js native, XHR, and Mock adapters, interceptors, observers, retries, cookies, and redirect control
- 🚀 Lifecycle Management - Orchestrate startup, shutdown, and runtime control of application components with dependency resolution
- 🪵 Flexible Logger - Sink-based logger with log levels, redaction, and service scoping
- 🔄 Retry Utilities - Fixed and exponential backoff strategies with cancellation support
- 📡 Event Systems - Event emitters for multiple event types and single-event observers with type safety
- 🛡️ Error Handling - Serialize errors for IPC/RPC, format them as readable tables, and handle callbacks safely
- 🔧 Common Utilities - ID generation (UUID, ULID, ObjectID), string manipulation, deep cloning, and more
- 📦 Tree-shakeable - Import only what you need via subpath exports
- 💪 TypeScript-first - TypeScript definitions for every published entry point
Installation
npm install lifecycleion
# or
yarn add lifecycleion
# or
bun add lifecycleionPeer Dependency: tldts
Lifecycleion declares tldts as a required peer
dependency. It carries the compiled Public Suffix List that http-client's CookieJar
scopes cookies with and that domain-utils re-exports, and it is a peer rather than a
direct dependency for two reasons: a compatible shared installation avoids duplicate PSL snapshots, and you can refresh the list by upgrading tldts within its
supported range without waiting on a Lifecycleion release.
Ensure your installation includes a version of tldts satisfying ^7.4.10. If your
package manager does not install peers automatically, or that behavior is disabled,
install it explicitly:
npm install 'tldts@^7.4.10'tldts is imported at module load by lifecycleion/http-client and
lifecycleion/domain-utils. A missing peer prevents those entry points from loading.
The peer allows consumers to update the PSL within the supported range, but does not
itself guarantee that a dependency tree contains only one version.
For Node.js runtimes, Lifecycleion currently targets Node >=25. Some libraries, including safe-handle-callback, logger's error listener, and lru-cache's onChange, report errors on the standard global 'error' event channel: an ErrorEvent dispatched through the global EventTarget methods. Those are web-standard primitives, and browsers, Bun, and Deno expose them on globalThis natively.
Standalone rendering and redaction failures use that same channel when you have not set a handler, so a logger.registerReportErrorListener() records them like any other reported failure. Failures raised by the logger itself use a separate asynchronous diagnostic channel: its 'diagnostic' event, then diagnosticSinks (or the regular sinks when none were configured), then guarded console.error. Diagnostic writes do not run through the logger again. See Where Failures Go.
Node.js is a partial case: ErrorEvent is native in Node 25+, but globalThis is still not an EventTarget, so Lifecycleion automatically supplies the missing global event methods without overwriting native or user-installed implementations. See global-event-target.
Quick Example
import {
LifecycleManager,
BaseComponent,
} from 'lifecycleion/lifecycle-manager';
import { ConsoleSink, Logger } from 'lifecycleion/logger';
import { RetryRunner } from 'lifecycleion/retry-utils';
// Create a logger
const logger = new Logger({ sinks: [new ConsoleSink()] });
// Set up retry logic
const runner = new RetryRunner(
{ strategy: 'fixed', maxRetryAttempts: 3, delayMS: 1000 },
async (reportResult) => {
// Your operation here
reportResult('success');
},
);
await runner.run(true);
// Manage component lifecycle
class MyComponent extends BaseComponent {
constructor() {
super(logger, { name: 'my-component' });
}
async start() {
logger.info('Starting component');
}
async stop() {
logger.info('Stopping component');
}
}
const manager = new LifecycleManager({ logger });
await manager.registerComponent(new MyComponent());
const startup = await manager.startAllComponents();
if (!startup.success) {
await logger.close();
throw new Error(startup.reason);
}
// Run the application, then release component and logger resources.
await manager.stopAllComponents();
await logger.close();Tip: listen for lifecycle-manager:shutdown-completed when you want one place to react to shutdown results from manual stops, signals like SIGINT / SIGTERM, or logger-exit hooks. This is the centralized hook for logging or follow-up policy when timedOut is true or stalledComponents is non-empty. If timedOut is true, the payload reflects the result when the manager stopped waiting. A stop already in flight remains protected against per-component overlap, while exit handling and later shutdown/escalation attempts may proceed. Use repeated shutdown escalation separately when you want additional shutdown requests to retry or force behavior.
Available Libraries
Each library has reference documentation in the docs folder. Click a library name below for its API notes and examples.
| Library | Import Path | Description |
| ------------------------------------------------------------------ | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| arrays | lifecycleion/arrays | Array utility functions for filtering, comparison, deduplication, and string manipulation |
| ascii-tables | lifecycleion/ascii-tables | Key-value and multi-column ASCII tables with word wrapping, nesting, and emoji support |
| clamp | lifecycleion/clamp | Number clamping utilities with safe handling for non-finite values and nullish inputs |
| constants | lifecycleion/constants | Common string constants including whitespace helpers and Python-style character sets |
| curly-brackets | lifecycleion/curly-brackets | String templating with {{placeholders}}, fallbacks, escaping, and compiled templates |
| datamask | lifecycleion/datamask | Mask emails, domains, and strings by proportion, counting in characters so a cut never splits an emoji |
| deep-clone | lifecycleion/deep-clone | Deep clone utility with circular reference detection for objects, arrays, Maps, Sets, and more |
| dev-mode | lifecycleion/dev-mode | Runtime-settable dev/production mode flag with auto-detection from CLI args or NODE_ENV |
| domain-utils | lifecycleion/domain-utils | Hardened helpers for normalizing and matching domains and origins for CORS and routing, with IDNA/TR46, IPv6, and wildcard semantics |
| error-to-string | lifecycleion/error-to-string | Format errors into readable ASCII tables with support for nested info and sensitive field masking |
| event-emitter | lifecycleion/event-emitter | Lightweight event emitter with protected and public variants, type safety, and memory management |
| global-event-target | lifecycleion/global-event-target | Conservative polyfill giving globalThis the EventTarget methods on Node.js, so 'error' event dispatch works there |
| http-client | lifecycleion/http-client (+ -node, -xhr, -mock) | Fluent HTTP client with Fetch, Node.js native, XHR, and Mock adapters, interceptors, observers, retries, cookies, and redirect control |
| id-helpers | lifecycleion/id-helpers | Unified ID generation and validation for ObjectID, UUID v4, UUID v7, and ULID |
| is-boolean | lifecycleion/is-boolean | Type guard to check if a value is a boolean |
| is-function | lifecycleion/is-function | Check whether a value is a function |
| is-number | lifecycleion/is-number | Type guards to check whether a value is a valid number, with and without finite enforcement |
| is-plain-object | lifecycleion/is-plain-object | Type guard to check if a value is a plain object (not null, not an array) |
| is-promise | lifecycleion/is-promise | Thenable/promise detection following the Promises/A+ specification |
| json-helpers | lifecycleion/json-helpers | JSON formatting utilities |
| lru-cache | lifecycleion/lru-cache | TTL-aware LRU cache with entry-count and size-based eviction, custom size calculators, and per-entry TTL overrides |
| lifecycle-manager | lifecycleion/lifecycle-manager | Lifecycle orchestration for managing startup, shutdown, and runtime control of application components |
| logger | lifecycleion/logger | Flexible sink-based logger with log levels, redaction, template strings, and service scoping |
| padding-utils | lifecycleion/padding-utils | String padding utilities for left, right, and center alignment with a configurable pad character |
| process-signal-manager | lifecycleion/process-signal-manager | Unified handler for process signals (SIGINT, SIGTERM, SIGHUP, etc.) and keyboard shortcuts with graceful shutdown and hot-reload support |
| promise-protected-resolver | lifecycleion/promise-protected-resolver | Promise wrapper with resolveOnce and rejectOnce that guarantee a promise is only settled once |
| retry-utils | lifecycleion/retry-utils | Retry logic with fixed and exponential backoff via RetryPolicy (low-level) and RetryRunner (high-level with events and cancellation) |
| safe-handle-callback | lifecycleion/safe-handle-callback | Safely execute sync or async callbacks with automatic error reporting on the standard 'error' channel (ErrorEvent + global EventTarget) |
| serialize-error | lifecycleion/serialize-error | Convert any Error into a plain JSON-serializable object and back again for IPC, RPCs, and database storage |
| single-event-observer | lifecycleion/single-event-observer | Lightweight type-safe observer pattern for a single event type, with public and protected notify variants |
| sleep | lifecycleion/sleep | Pause async execution for a given number of milliseconds |
| strings | lifecycleion/strings | String type guard, case conversion (PascalCase, camelCase, CONSTANT_CASE), grapheme splitting, character filtering, and chopping helpers |
| tmp-dir | lifecycleion/tmp-dir | Create uniquely named temporary directories with explicit cleanup, configurable prefix, postfix, and unsafe cleanup support |
| stringify-value | lifecycleion/stringify-value | Render any value as a display string, or return it with parts redacted |
| to-error | lifecycleion/to-error | Coerce any thrown or rejected value into an Error (toError), or describe it as a string that is always safe to read (describeError) |
| unix-time-helpers | lifecycleion/unix-time-helpers | Unix timestamp utilities for seconds, milliseconds, high-resolution timing, and unit conversion |
Change Log
See changelog.md for version history and release notes.
Contributing
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests on GitHub.
License
MIT License - see LICENSE file for details.
