Skip to Content
HeronJS v4 is now available.
Knowledge BaseFramework Knowledge

Framework Knowledge

This guide explains how HeronJS applications are composed, how components execute, and which resources the framework owns. It applies to version 4.0.0.

Use the Knowledge Catalog to find a package or source submodule. Use the Knowledge Graph to inspect package dependencies and submodule ownership. For a runnable application, start with Getting Started.

Core concepts

ConceptMeaning
Framework packageA published @heronjs/* package with a defined responsibility and public entrypoint.
Source submoduleA feature directory within a package, such as common/di or core/lifecycle. It is not automatically a public import path.
Application moduleA class decorated with @Module that declares components and imports other application modules.
ProviderAn injectable component containing application logic or access to a resource.
ContainerThe application’s dependency-injection container, responsible for provider resolution and owned instance disposal.
RegistryApplication-local component registrations used during composition and runtime initialization.
Protocol extensionAn adapter that connects declared handlers to a protocol while participating in application lifecycle management.
Execution resultA value, Promise, Observable, or Promise resolving to an Observable, consumed according to the protocol’s execution contract.
WorkerA separate execution context with its own module instances and DI container.

Application composition

Decorators record metadata. A module declaration identifies the providers, controllers, services, and protocol handlers that belong to an application. Bootstrap reads that metadata and builds a registration plan; importing a decorated class alone does not create a global application instance.

Use module imports to compose features. Module traversal uses constructor identity, handles repeated imports and cycles, and respects explicit export declarations. Import framework APIs through their public package entrypoints rather than internal source paths.

Module fieldRegistered components
importsOther application modules
providersInjectable application components
controllersHTTP controllers
servicesInitialization, interval, and daemon services
graphqlsGraphQL schema and resolver classes
websocketsNative WebSocket handlers
rpcstRPC procedure groups
mcpsMCP catalog controllers
acpsACP agents
transportersMessaging components

Use @Stores and @DataSources to declare cache and database resources. See Dependency Injection, Stores, and Data Sources for configuration and ownership rules.

Application lifecycle

StageFramework behaviorApplication responsibility
DeclarationDecorators record configuration and component metadata.Declare components and their module relationships.
CreationHeronJS.create({module}) creates application-local state and bootstraps owned resources.Provide validated configuration and handle initialization failures.
Startupapp.listen(...) starts the shared HTTP listener after extension registration. app.start() also supports explicitly selected stdio execution.Select the transport and configure protocol endpoints before startup.
ExecutionAdapters resolve handlers, evaluate guards, bind inputs, and consume results.Validate untrusted input and observe cancellation during long-running work.
Shutdownawait app.close() stops owned execution and disposes resources.Await cleanup in tests and scripts; dispose resources that remain externally owned.

Each application has its own container, registry, protocol extensions, services, and resources. Repeated or concurrent close calls share completion. Cleanup attempts remaining disposers even when one fails, and aggregated failures remain available to the caller.

Dependency injection and ownership

Use constructors or Token<T> to associate a registration with its value type. String and symbol lookups return unknown and require validation before use. Typed metadata keys enforce the same relationship between stored configuration and its reader.

An instance registered with registerInstance remains owned by its caller. Use registerOwnedInstance or onDispose when the container should release the resource. Register cleanup for factory-created resources explicitly.

Worker containers are isolated from the parent application. Pass cloneable data across the worker boundary; use declared parent-service RPC interfaces when a worker needs access to a parent-owned service. See Thread for job scopes, service lifetimes, and shutdown behavior.

Execution and cancellation

Unary protocol operations consume the first emission of an Observable and then unsubscribe. Streaming APIs consume emissions until completion or cancellation. Finite lifecycle hooks and message-consumer operations wait for completion.

Use Reactive.call to defer invocation until subscription and preserve the receiver. Use Reactive.first for a unary result or Reactive.complete when completion is the relevant outcome. An empty unary result is an error; an emitted undefined remains a value, subject to protocol validation.

Disconnects, protocol cancellation, and application shutdown cancel framework-owned Observable execution. Native Promises require cooperative cancellation in application code. Observe the supplied abort signal and release application-owned work when it is aborted. The Reactive Execution guide defines behavior for each protocol.

Protocol boundaries

Core owns the shared HTTP listener. HTTP, GraphQL, tRPC, WebSocket, MCP, and ACP extensions register their endpoints through the application lifecycle. Authentication, validation, error mapping, and transport semantics remain specific to each protocol.

HTTP is the default transport. MCP and ACP can use stdio when explicitly configured, but only one endpoint can own process stdio. Messaging adapters retain broker-specific acknowledgement and shutdown behavior.

Selecting an execution model

WorkloadComponent
Request/response logicHTTP controller, GraphQL resolver, or tRPC procedure
Connection-oriented eventsWebSocket handler
Tool, resource, or prompt catalogMCP controller
Agent sessions and promptsACP agent
Startup or recurring background workService on the main thread
CPU-bound jobs or isolated long-running workWorker pool or dedicated worker service
Broker-driven processingEBS consumer or publisher

Review the Migration Guide before moving an existing 3.7.11 application to 4.0.0. Both versions remain LTS; their documentation and examples are versioned separately.

This guide is based on the 4.0.0 module and lifecycle implementation .

Last updated on