constructor
LifecycleCreates a synchronous lifecycle. When an abort-compatible signal is supplied, aborting that signal destroys the lifecycle. An already-aborted signal creates an already-destroyed lifecycle.
Reference
Typed lifetime, event, and resource management for JavaScript and TypeScript.
Start
pnpm add @gottheflag/lifecyclenpm install @gottheflag/lifecycleyarn add @gottheflag/lifecyclebun add @gottheflag/lifecycleStart
Node.js18.18.0 or newer.TypeScript5.2 or newer for TypeScript consumers.SuppressedErrorRuntimes without a native implementation need a polyfill only when both a using block body and its disposal throw.Package surface
LifecycleClassSynchronous lifetime, ownership, cleanup, child, and event management.
AsyncLifecycleClassAsynchronous lifetime management with awaited teardown.
LifecycleOptionsTypeConstructor options accepted by Lifecycle.
LifecycleSignalTypeEnvironment-agnostic structural contract for an abort-compatible signal.
NoEventsTypeEmpty event map used by lifecycles with no typed events.
CleanupTypeSynchronous cleanup callback.
AsyncCleanupTypeSynchronous or asynchronous cleanup callback.
DestroyableTypeResource exposing synchronous destroy().
AsyncDestroyableTypeResource exposing sync or async destroy().
EventArgumentsTypeConditional argument tuple used by typed event emission.
EventListenerTypeTyped synchronous event listener.
Class
Owns everything associated with one synchronous lifetime: deferred cleanup, destroyable resources, child lifecycles, and typed event listeners.
Creates a synchronous lifecycle. When an abort-compatible signal is supplied, aborting that signal destroys the lifecycle. An already-aborted signal creates an already-destroyed lifecycle.
Indicates whether destruction has started. Once true, it never becomes false.
Registers synchronous cleanup work. Returns an exactly-once cleanup function that can execute the registered cleanup early and remove it from lifecycle teardown.
Registers a synchronous destroyable resource with the lifecycle and returns the same resource unchanged.
destroy(): void.Creates an independently typed child lifecycle owned by the parent. Destroying the child early detaches it from the parent. Destroying the parent destroys every still-owned child.
Ends the lifecycle exactly once. Event delivery stops first, then active cleanup entries run in reverse registration order. Every cleanup is attempted even when another cleanup throws.
Delegates to destroy() and makes the lifecycle compatible with synchronous explicit resource management.
Class
Asynchronous counterpart to Lifecycle. Cleanup entries may return promises and are awaited sequentially in reverse registration order. Event dispatch remains synchronous.
Indicates whether asynchronous destruction has started. It may be true while cleanup work is still being awaited.
Registers synchronous or asynchronous cleanup work and returns an exactly-once cleanup function that may be awaited when executed early.
Owns a resource whose destroy() method may complete synchronously or return a promise-like value.
Creates an independently typed asynchronous child owned by the parent. Early child destruction detaches it from parent teardown.
Starts teardown once and returns the destruction promise. Cleanup entries are awaited sequentially in reverse registration order. Concurrent calls receive the same promise.
Delegates to destroy() and makes the lifecycle compatible with asynchronous explicit resource management.
Shared API
Both lifecycle classes expose the same typed synchronous event API. Event spaces belong to each lifecycle independently and do not inherit or bubble between parent and child lifecycles.
Registers a synchronous listener for an event key. Returns an exactly-once unsubscribe function.
Registers a synchronous listener that unsubscribes before its first invocation. Returns an unsubscribe function for cancellation before emission.
Synchronously dispatches an event to the listeners registered on that lifecycle. Void events require no payload. Emission after destruction is ignored.
Removes every event listener or every listener for one event key. It does not run deferred cleanup, destroy resources, or destroy child lifecycles.
Contract
Lifecycle accepts an abort-compatible signal. Aborting it triggers synchronous destruction. Manual destruction removes the abort listener. AsyncLifecycle currently has no signal constructor option.
Contract
Children are ownership relationships, not event inheritance. A child may have a different event map. Parent destruction destroys live children; early child destruction detaches that child from its parent.
Contract
Active cleanup entries are executed in reverse registration order. This applies to deferred callbacks, owned resources, and children because each is represented in the same teardown sequence.
Contract
Destruction attempts every active cleanup even when earlier cleanup fails. Multiple failures are reported through AggregateError. Event emission also completes listener delivery before collected listener failures are reported.
Contract
defer() after destruction executes immediately. Consequently, late own() destroys immediately and late child() returns an already-destroyed child. New event subscriptions are rejected.
New cleanup, ownership, child, and event subscriptions are rejected after destruction starts because asynchronous cleanup cannot be completed synchronously at registration time.
Reference
Cleanup() => voidAsyncCleanup() => void | PromiseLike<void>Destroyable{ destroy(): void }AsyncDestroyable{ destroy(): void | PromiseLike<void> }LifecycleOptions{ signal?: LifecycleSignal }LifecycleSignal{ readonly aborted: boolean; addEventListener(...); removeEventListener(...) }NoEventsRecord<never, never>EventArguments<TPayload>void payload → []; otherwise [payload]EventListener<TPayload>typed synchronous listener