← All @molecule/* packages · App templates
@molecule/api-server-default-expressFeature · server-default · API (Node) · v1.0.1 · Apache-2.0
Default Express server factory: bonds setup, DB migrations, body/cookie/cors middleware, /api router mount, /health endpoint, 401 normalization, optional HTTPS via self-signed pem certs. Extracts 80-line server.ts shipped by 79 fleet apps.
npm install @molecule/api-server-default-express@molecule/api-server-default-express is a ready-made server-default feature for the API (Node) side. It composes the core interfaces it needs, so it works with whichever providers your app has bonded.
import { createServerFactory } from '@molecule/api-server-default-express'
// In your app's api/src/server.ts these come from the scaffolded files:
// import { setupBonds } from './bonds/index.js'
// import { runMigrations } from './scripts/migrate.js'
const create = createServerFactory({
setupBonds,
runMigrations,
// Router loads lazily AFTER setupBonds() so bond-conditional route
// maps see fully-registered providers. The module must export
// `router`. In your app: getRouter: () => import('./App/router.js')
getRouter: async () => ({ router }),
})
// Runs migrations → wires bonds → mounts middleware + router at /api →
// listens on PORT (default 4000). The scaffolded server.ts exports
// `create` and invokes it when the file is run directly.
await create()Works with: @molecule/api-error-tracking, @molecule/api-logger, @molecule/api-middleware-body-parser, @molecule/api-middleware-cookie-parser, @molecule/api-middleware-cors, @molecule/api-secrets
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
@molecule/api-server-default-express — drop-in Express server
factory used by the molecule fleet's api/src/server.ts.
createServerFactory({ setupBonds, runMigrations, getRouter })
returns a (port?) => Promise<server> function that runs
migrations, wires bonds, mounts router + middleware, and starts
an HTTP (or self-signed HTTPS for local dev) listener.
import { createServerFactory } from '@molecule/api-server-default-express'
// In your app's api/src/server.ts these come from the scaffolded files:
// import { setupBonds } from './bonds/index.js'
// import { runMigrations } from './scripts/migrate.js'
const create = createServerFactory({
setupBonds,
runMigrations,
// Router loads lazily AFTER setupBonds() so bond-conditional route
// maps see fully-registered providers. The module must export
// `router`. In your app: getRouter: () => import('./App/router.js')
getRouter: async () => ({ router }),
})
// Runs migrations → wires bonds → mounts middleware + router at /api →
// listens on PORT (default 4000). The scaffolded server.ts exports
// `create` and invokes it when the file is run directly.
await create()
feature
npm install @molecule/api-server-default-express @molecule/api-error-tracking @molecule/api-logger @molecule/api-middleware-body-parser @molecule/api-middleware-cookie-parser @molecule/api-middleware-cors @molecule/api-secrets express
npm install -D @types/express
CreateServerOptionsOptions for createServerFactory.
interface CreateServerOptions {
/** App-specific bond wiring (resolves secrets + wires providers). */
setupBonds: () => Promise<void>
/** DB migration runner (typically the `createMigrator()`-bound function). */
runMigrations: () => Promise<void>
/**
* Lazy router import. Loaded AFTER `setupBonds()` so bond-conditional
* route maps see fully-registered providers at module-evaluation time.
*/
getRouter: () => Promise<{ router: express.Router }>
/**
* Optional hook to mount middleware AFTER cors+cookieParser but
* BEFORE the body parser. Use this for routes that need their own
* multipart streaming (file uploads via busboy) — the body parser's
* `files: 0` config would silently consume the multipart stream.
*/
preBodyParser?: (app: express.Express) => Promise<void> | void
/**
* Optional hook called after `setupBonds()` but before the router
* import. Use for additional one-shot setup (e.g. entitlements
* tier-registry registration that runs after the bonds are wired).
*/
postBondsSetup?: () => Promise<void> | void
/**
* Optional hook to mount middleware on `/api` BEFORE the canonical
* `app.use('/api', router)` mount. Use for app-specific authed
* content handlers (`/api`-prefixed) that need to run before the
* resource router.
*/
preApiRouter?: (app: express.Express) => Promise<void> | void
}
TaggedErrorA deliberately-tagged molecule error mapped to a real HTTP status by the API.
interface TaggedError {
/** HTTP status to return (e.g. 503 for a missing provider config). */
statusCode: number
/** Machine-readable key the app/IDE maps to a friendly message. */
errorKey: string
/** Human-readable message. */
message: string
}
classifyTaggedError(error)Classify a thrown value for the API error middleware. Returns a {@link TaggedError}
ONLY for values deliberately tagged by molecule with BOTH a numeric statusCode
AND a string errorKey — e.g. a provider's config-missing throw (statusCode: 503,
errorKey: 'config.notConfigured'). These are expected, actionable conditions a
user must resolve (a missing STRIPE_SECRET_KEY is theirs to set, not a server bug),
so the middleware surfaces the real status + errorKey instead of an opaque 500 — the
app/IDE can then show "configure X to enable this feature".
Requiring BOTH fields is deliberate: it keeps arbitrary library errors that merely
carry a .statusCode (e.g. an AWS SDK error) from being silently surfaced with a
status molecule never chose. Returns null for everything else (→ default 500 path).
function classifyTaggedError(error: unknown): TaggedError | null
error — The thrown value caught by the error middleware.Returns: The classified tagged error, or null if it isn't a molecule-tagged error.
createServerFactory(opts)Returns an Express server-creation function bound to the given
setupBonds / runMigrations / router loaders. The returned create
builds the canonical molecule fleet server:
bodyParser / cookieParser / cors middleware applied./api./health endpoint with { status: 'ok', timestamp }.Unauthorized / Unauthorized. errors normalized to 401.process.env.HTTPS is set, using self-signed
certs from optional dependency pem.process.on('uncaughtException') + unhandledRejection registered
on first call (idempotent across multiple create() invocations).function createServerFactory(
opts: CreateServerOptions,
): (port?: number) => Promise<express.Express | https.Server>
errorMiddleware(error, req, res, _next)Terminal Express error middleware for the canonical molecule fleet server.
Resolves a thrown value to exactly one of three sanitized responses and NEVER
delegates to Express's built-in finalhandler:
Unauthorized / Unauthorized. → 401 with the string body
(so authSelf-style middleware routes to 401 instead of a 500 page).statusCode + { error, errorKey } JSON (expected, user-actionable config
conditions, e.g. a missing STRIPE_SECRET_KEY → 503 config.notConfigured).500 { error: 'Internal Server Error' }, logged server-side AND
reported to the bonded error tracker (@molecule/api-error-tracking's
captureException, a documented no-op when no tracker is bonded).Only case 3 is captured: cases 1–2 (401s, tagged config-missing 503s, and any other tagged 4xx/5xx) are expected, user-actionable conditions — not defects — so reporting them would drown real faults in noise.
Case 3 is the security-critical branch: it is safe-by-construction and does NOT
depend on NODE_ENV. Calling next(error) here would fall through to Express's
finalhandler, which embeds err.stack in the HTTP response body whenever
app.get('env') !== 'production' (the default when NODE_ENV is unset or
development), disclosing absolute server paths, module layout, dependency
versions, and query/data fragments. Returning the opaque 500 unconditionally
removes that leak for every flagship app regardless of how it is deployed.
function errorMiddleware(
error: any,
req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>,
res: Response<any, Record<string, any>, number>,
_next: NextFunction,
): void
error — The thrown value caught by Express.req — The request (used only as capture context for error tracking).res — The response to write the sanitized error to._next — The next function (intentionally never called for untagged errors).registerServerCreatedHook(hook)Register a hook to run with the HTTP(S) server right before it listens.
Typically called from a bond's setup (e.g. setupRealtimeSocketio) during
setupBonds(), which runs earlier in create() than server construction.
function registerServerCreatedHook(
hook: (server: http.Server | https.Server) => void | Promise<void>,
): void
hook — Receives the real http.Server/https.Server.securityHeadersMiddleware(_req, res, next)Global browser-security headers applied to EVERY response (mounted before the
routers in createServerFactory, mirroring the molecule.dev platform server).
Defaults are conservative and framework-agnostic — no app-specific CSP source lists, just the clickjacking / MIME-sniffing / referrer baseline a JSON API should always ship:
X-Content-Type-Options: nosniff — stop MIME-type sniffing.X-Frame-Options: DENY + Content-Security-Policy: frame-ancestors 'none'
— anti-clickjacking. A generated app that intends to be embedded (iframe)
can override these in its own middleware.X-XSS-Protection: 0 — disable the legacy, buggy XSS auditor (modern
correct value; CSP is the real defense).Referrer-Policy: strict-origin-when-cross-origin — don't leak full URLs
cross-origin.Strict-Transport-Security — production only (mirrors the platform server's
NODE_ENV check) so local plain-HTTP dev isn't force-upgraded to HTTPS.function securityHeadersMiddleware(
_req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>,
res: Response<any, Record<string, any>, number>,
next: NextFunction,
): void
_req — The request (unused).res — The response to set headers on.next — Express next.Peer dependencies:
@molecule/api-error-tracking ^1.0.1@molecule/api-logger ^1.0.1@molecule/api-middleware-body-parser ^1.0.1@molecule/api-middleware-cookie-parser ^1.0.1@molecule/api-middleware-cors ^1.0.1@molecule/api-secrets ^1.0.1express ^4.0.0 || ^5.0.0@molecule/api-error-tracking@molecule/api-logger@molecule/api-middleware-body-parser@molecule/api-middleware-cookie-parser@molecule/api-middleware-cors@molecule/api-secretsexpress