Pages
Contents
@xpulse/app β Component Spec
Status: ACCEPTED Β· Updated March 2026 Parent:
GLOBAL_concept-ecosystem.md
Overview
Entry point for every xPart. Bootstraps the entire stack via a resilient service loader and provides the app root as well as environment helpers.
Two responsibilities: bootstrap the stack + provide the app root β nothing more.
@xpulse/app is the only permitted place in the ecosystem that "knows everything".
All other packages remain fully decoupled.
Dependencies
Two hard dependencies that are always required:
@xpulse/eventβ event bus (ADR-010)@xpulse/configβ loadsxpulse.json+.env
The standard stack is shipped as dependencies for convenience and
auto-discovered by the service loader at runtime:
@xpulse/logger, @xpulse/http, @xpulse/router,
@xpulse/template, @xpulse/theme, @xpulse/controller.
@xpulse/debug and @xpulse/dev are optional β no error if not installed.
Feature packages (@xpulse/doc, etc.) are installed explicitly by the app.
API
app.init(env?)
Bootstraps the entire stack via the resilient service loader. Always everything β no selective loading.
| import app from '@xpulse/app'; |
| // env from APP_ENV β NODE_ENV β null |
| await app.init(); |
| // explicit env |
| await app.init('stage'); |
| await app.init('production'); |
app.start() / app.stop()
| app.start(); // blocking |
| await app.stop(); // graceful shutdown |
Typical index.js
| import app from '@xpulse/app'; |
| await app.init(); |
| app.start(); |
| process.on('SIGTERM', () => app.stop()); |
| process.on('SIGINT', () => app.stop()); |
Environments
| Value | Description |
|---|---|
development |
Local development |
stage |
Staging environment β RC testing |
production |
Production environment |
Additional environments are allowed but undocumented.
APP_ENV takes precedence over NODE_ENV.
App Root
The directory where xpulse.json lives β typically process.cwd().
Set on the first app.init() call and immutable thereafter.
All paths in the ecosystem are defined relative to the app root.
Helper Methods
app.root()
Returns the absolute app root path.
| app.root() |
| // β '/var/www/my-app' |
app.path(relative)
Resolves a relative path starting from the app root.
| app.path('src/templates') // β '/var/www/my-app/src/templates' |
| app.path('var/cache/template') // β '/var/www/my-app/var/cache/template' |
| app.path('var/log') // β '/var/www/my-app/var/log' |
app.env
The current environment.
| app.env // β 'stage' | 'production' | 'development' | null |
app.isDev()
| app.isDev() // β true when env === 'development' |
app.isProd()
| app.isProd() // β true when env === 'production' |
app.isStage()
| app.isStage() // β true when env === 'stage' |
Bootstrap Order
app.init() works via a auto-discovery service loader β
packages declare their dependencies in xpulse.json, the loader resolves
the correct init order via topological sort. See service-loader.md.
| 1. Set app root + config.load() β xpulse.json + .env |
| 2. debug.bootstrapDebug() β only when debug.enabled |
| runs before loader so everything is debuggable |
| 3. Service loader β auto-discovers all installed @xpulse/* packages |
| with a service section in their xpulse.json |
| topological sort by depends[] |
| resilient: missing or disabled packages are skipped |
@xpulse/event does not need an init() β zero dependencies, works on import.
@xpulse/dev is a separate system β hooks in from the outside, loader ignores it.
Graceful Shutdown
| 1. Stop accepting new requests |
| 2. Complete running requests (timeout: 30s) |
| 3. Flush @xpulse/logger |
| 4. process.exit(0) |
Emitted Events
| Event | Payload | When |
|---|---|---|
app:init |
{ env, root } |
Bootstrap begins |
app:ready |
{ env, root, uptime } |
Entire stack ready |
app:stopping |
{ signal } |
SIGTERM / SIGINT received |
app:stopped |
{ uptime, exitCode } |
Shutdown complete |
app:service:ready |
{ service } |
Service initialised successfully |
app:service:skipped |
{ service, reason } |
Not installed or load: false |
app:service:error |
{ service, error } |
Init threw, loader continues |
The complete event reference for all packages is in GLOBAL_adr-010-event-driven.md.
Receipt
@xpulse/app ships a receipt that is automatically executed on npm install.
receipt/up.js creates (only if not already present):
| File | Contents |
|---|---|
src/index.js |
Minimal runnable app |
xpulse.json |
Minimal configuration (name, type) |
.npmrc |
Registry reference to npm.xpulse.one |
.env.example |
Documented example variables |
receipt/down.js: Warning β no automatic deletion.
.env.example Contents
| # xPulse App β Environment Variables |
| # Copy this file to .env and adjust the values |
| # Server |
| PORT=3000 |
| # Environment: development | stage | production |
| APP_ENV=development |
| # Logging |
| LOG=true |
| DEBUG=false |
Package Structure
| @xpulse/app/ |
| src/ |
| index.js β default export: app object |
| bootstrap/ |
| app.js β app root + config.load() |
| services.js β auto-discovery service loader (reads xpulse.json, topo-sort) |
| receipt/ |
| up.js |
| down.js |
| files/ |
| src/ |
| index.js |
| xpulse.json |
| .npmrc |
| .env.example |
| test/ |
| app.test.js |
| docs/ |
| index.md |
| de/ index, guide, api |
| en/ index, guide, api |
| Dockerfile |
| Makefile |
| README.md |
| package.json |
| xpulse.json |