Create App

The framework's entry point. One call opens the vault, opens the database, builds a router carrying the security middleware, wires the jobs runner and the queue when they are configured, and resolves with the pieces an application serves from.

The middleware is on the router before any route is registered, so a route cannot be added outside the request lifecycle's protections. Nine of the eleven middlewares are installed without being asked for; cors and rateLimit wait for an origin list or a bound, because neither has a safe default. Turning one of the nine off records an app.middleware.disabled event in the audit chain, so the deployment's own posture is auditable rather than implicit.

Shutdown is phase-ordered through b.appShutdown: in-flight requests drain, then jobs, the queue, the router, the cluster and the databases. An application that calls shutdown() on SIGTERM survives a rolling restart without dropping a request.

b.createApp(opts) #

stable0.1.65
{
  dataDir:          string,   // required; created when absent
  port:             number,   // 0 binds an arbitrary free port
  host:             string,
  tls:              object,   // passed to the TLS server
  vault:            object,   // b.vault.init opts; mode defaults to "wrapped"
  db:               object,   // b.db.init opts
  schema:           array,    // table definitions for b.db.init
  frameworkSchema:  boolean,  // false skips the cluster schema check
  externalDb:       object,   // b.externalDb.init config
  cluster:          object,   // b.cluster.init config
  queue:            object,   // b.queue.init config
  jobs:             object,   // function (jobs) registering handlers
  jobsOptions:      object,   // b.jobs.create opts
  middleware:       object,   // per-middleware opts, or false to omit one
  routes:           object,   // function (router) registering routes
  shutdown:         object,   // graceMs, installSignalHandlers, afterDrain
}

Open the vault, open the database, build a router with the security middleware already on it, and resolve with the pieces an application needs to serve: { router, db, vault, jobs, listen, address, shutdown, shutdownOrchestrator }.

dataDir is the only required option. The directory is created when it does not exist, and the vault opens in wrapped mode unless vault.mode says otherwise.

Nine middlewares are installed unless the matching middleware key is false: requestId, securityHeaders, botGuard, cookies, cspNonce, fetchMetadata, csrf, bodyParser and errorHandler. cors and rateLimit are installed only when their key is present, since both need an origin list or a bound to mean anything. Passing false for one of the nine records an app.middleware.disabled audit event, so an operator can see from the chain which defaults a deployment turned off.

Each of those eleven keys is false, true, or that middleware's options object, and anything else raises before the vault, the database or the job consumers are started, so a refused configuration leaves nothing running. A configuration file deserialized into the string "false", or a 0, or a null, would otherwise read as "not false, not an object" and take the middleware off without recording it, which is the one way to lose CSRF or the bot guard silently.

routes receives the router after the middleware is on it and before the error handler, which is why a route registered there is covered by both.

listen(listenOpts?) starts the server, taking port, host and tls from its own argument first and from createApp's options otherwise. address() answers the bound address once it is listening. shutdown() drains through the orchestrator: in-flight requests, then jobs, then the queue, the router, the cluster and the databases.

var b = require("@blamejs/core");
var app = await b.createApp({
  dataDir: "./data",
  port:    0,
  routes:  function (router) {
    router.get("/health", function (req, res) { res.json({ ok: true }); });
  },
});
await app.listen();
app.address().port;          // → the port it bound
await app.shutdown();

Last updated 2026-10-12T14:21:56.879Z by seeder.