Platform Services
Platform Services 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>Node runtime
@askrjs/node wires an Askr ServerApp into a real Node process: createNodeHandler turns it into a plain (req, res, next) function, listen binds a raw http.Server, and serve wraps both together with signal handling and an asset root. Nothing here depends on a specific host — the same app can run behind a reverse proxy, inside a container, or from a local script. If you're deploying to a serverless platform instead, you'll use that platform's adapter rather than this package.
Internationalization
@askrjs/i18n gives you createI18n(sourceLocale, catalogs), where catalogs are ordinary TypeScript functions rather than a message-key DSL. The source locale's function signatures become the required shape for every other locale, so a French catalog missing an argument or a key fails at compile time, not in production. Locale selection itself — reading a cookie, a URL prefix, a header — is left entirely to your application code.
Telemetry
@askrjs/otel's createTelemetry produces a Telemetry object with typed span helpers — request, loader, action, routeMatch, and more — each scoped to one of a fixed set of askr.* operation names. It talks to whatever OpenTelemetry provider your app installs via the standard @opentelemetry/api, and does nothing observable if you haven't installed one. Fields passed into spans are limited to a small allowlisted shape: request IDs, routes, status codes, durations — no request bodies or user data.
Composition
These three packages are independent and none of them requires the others — you can use @askrjs/i18n without touching telemetry, or run under @askrjs/node without ever calling createTelemetry. In practice most apps construct them once in a composition root alongside the server app, then thread the resulting i18n and telemetry instances through as plain values wherever loaders and actions need them.