# Platform Services

> Platform Services at the Askr server boundary, with validated input and explicit failure states.

Source: [https://askrjs.com/docs/platform-services](https://askrjs.com/docs/platform-services)

Status: stable. Packages: @askrjs/askr.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Create the platform service at the application composition root and pass its provider-neutral contract into routes or components.

```tsx
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.

## Documentation navigation

[Previous](https://askrjs.com/docs/mcp/stdio-transport/index.md) | [Next](https://askrjs.com/docs/platform-services/node-runtime/index.md)
