Node Runtime
Node Runtime at the Askr server boundary, with validated input and explicit failure states.
Example
Create the platform service at the application composition root and pass its provider-neutral contract into routes or components.
import { createI18n } from '@askrjs/i18n';
export const i18n = createI18n('en', {
en: { greeting: (name: string) => 'Hello, ' + name },
fr: { greeting: (name: string) => 'Bonjour, ' + name },
});
<i18n.Scope locale="en">
{i18n.text('greeting', 'Askr')}
</i18n.Scope>Server adapter
createNodeHandler(app, options) converts a ServerApp into a Node-compatible (req, res, next?) => void handler — options is a required second argument, not optional, even if you have nothing to configure and pass {}, so it drops straight into an existing http.createServer callback or a Connect/Express-style middleware chain. The optional baseUrl lets you tell the adapter where the app is mounted when it isn't serving from the root path. Everything else about request handling — routing, loaders, actions — stays inside the ServerApp itself; this layer just bridges Node's I/O types to it.
MCP adapter
connectMcpStdio(mcp, options), exported from @askrjs/node/mcp, runs an @askrjs/server McpServer over stdio instead of HTTP — the shape you need when the client is a local MCP host rather than a browser. You supply dependencies directly, along with optional input/output/diagnostics streams and an auth value or resolver function for authenticating the connection. The returned McpStdioConnection exposes a closed promise and a close() method, so you can shut the process down cleanly instead of just letting the pipes drop.
Signals and shutdown
serve accepts a signals option — an array of NodeJS.Signals to listen for, or false to disable the behavior entirely — and installs handlers that call your app's optional close() and then resolve serve's returned promise. listen, the lower-level function, instead accepts a plain AbortSignal if you want to control shutdown from your own lifecycle logic rather than OS signals. Either way, the goal is the same: give in-flight requests a chance to finish before the process exits.
Deployment
serve(app, options) is the one-call path for a standalone process: it binds a port and host, optionally serves static assets from an assets.root directory, and returns a ServedApplication with the live server, its resolved url, and a close() method. For finer control — custom TLS setup, a shared HTTP server, integration with an existing process manager — call listen or createNodeHandler directly instead. Nothing in this package assumes a particular host provider; it's plain Node http, so it runs anywhere Node runs.