App API

primate/app validates application configuration and returns the application facade exported by config/app.ts.

import app from "primate/app";
import type { AppFacade } from "primate/app";

See the Configuration guide for deployment advice and examples, the Application guide for facade usage, and the Modules guide for writing extensions.

app()

function app<
  P extends EnvSchema = EnvSchema,
  const I extends I18NConfig | undefined = undefined,
  const T extends Record<string, string> = Record<string, string>,
  D extends DB = DB,
>(input?: ConfigInput<P, I, T, D>): AppFacade<P, I, D>;

Parameters: input is optional and defaults to {}. Pema validates it, applies defaults, and rejects invalid values. http.timeout is explicitly closed and rejects unknown members.

Returns: An AppFacade<P, I, D> preserving the inferred environment, localization, and migration-database types.

Throws: A Pema parse error for invalid configuration. Removed db.migrations.autoapply, client.groups, and numeric http.timeout forms produce migration diagnostics instead of being ignored.

// config/app.ts
import app from "primate/app";

export default app({
  http: { port: 8080 },
});

ConfigInput

ConfigInput is an inferred supporting type, not a named export from primate/app. The following expanded shape represents the current public input contract; generic refinements preserve partition, environment, i18n, and database inference.

primate/config remains a deprecated compatibility entrypoint. Calling its factory emits a diagnostic directing applications to primate/app; it otherwise uses the same implementation and validation behavior.

type ConfigInput<P, I, T, D> = {
  build?: { external?: string[] };
  conditions?: string[];
  client?: {
    partitions: T;
    routes: Record<string, keyof NoInfer<T> & string>;
  };
  http?: {
    csp?: Record<string, string[]>;
    headers?: Record<string, string>;
    host?: string;
    port?: number;
    timeout?: {
      inactivity?: number;
      request?: number;
      headers?: number;
    };
    ssl?: { cert?: string; key?: string };
    static?: { root?: string };
  };
  livereload?: {
    exclude?: string[];
    host?: string;
    port?: number;
  };
  migrations?: { table: string; db: D };
  env?: { schema?: ObjectType<P> };
  i18n?: I;
  loaders?: Record<string, "file">;
  entrypoints?: Record<string, string>;
  modules?: Module[];
};

input.build.external

build?: { external?: string[] };

Packages or import paths excluded from the production server bundle. The default is []; duplicate entries are rejected. External packages must be available in the production installation.

input.conditions

conditions?: string[];

Additional package export conditions used by client and server builds. The default is []; duplicate entries are rejected.

input.client

client?: {
  partitions: Record<string, string>;
  routes: Record<string, string>;
};

Defines isolated client bundles and maps route prefixes to partition names. Both maps are required when client is present. Route values are constrained to inferred partitions keys. The complete prefix and isolation rules are in the Configuration guide.

input.http.csp

csp?: Record<string, string[]>;

Content-Security-Policy directives. No policy is emitted by default.

input.http.headers

headers?: Record<string, string>;

Default response headers added while rendering application views. The default is no additional headers.

input.http.host

host?: string;

Server host. Defaults to HOST from the environment, then "localhost".

input.http.port

port?: number;

Unsigned valid TCP port. Defaults to numeric PORT from the environment, then 6161.

input.http.timeout

timeout?: {
  inactivity?: number;
  request?: number;
  headers?: number;
};

Optional whole-millisecond network clocks. inactivity accepts 0 through 255000; request and headers accept 0 through 2147483647. Omitted members preserve runtime defaults. Runtime support and interactions are listed in the Configuration guide.

input.http.ssl

ssl?: { cert?: string; key?: string };

Certificate and private-key paths. HTTPS is active only when both are defined. Both values default to undefined.

input.http.static.root

static?: { root?: string };

URL root under which files from the application static directory are served. Defaults to "/".

input.livereload

livereload?: {
  exclude?: string[];
  host?: string;
  port?: number;
};

Development live-reload exclusions and endpoint overrides. host defaults to the configured HTTP host and port defaults to one less than the configured HTTP port when Primate resolves the live-reload endpoint.

input.migrations

migrations?: { table: string; db: DB };

Configures the application migration ledger and preserves db in the returned facade's migration declaration type. There is no default migration ledger; migrations are applied explicitly rather than at server startup.

input.env.schema

env?: { schema?: ObjectType<EnvSchema> };

Pema object schema for environment values. When present, values are parsed when the server facade is attached and app.env() becomes key- and result-typed. The default is no schema.

input.i18n

i18n?: I18NConfig;

Localization configuration. The default is undefined, which installs the missing-i18n facade. See the primate/i18n API and Internationalization guide.

input.loaders

loaders?: Record<string, "file">;

Maps file extensions to esbuild loaders. The only accepted value is "file". The default is no additional loader mapping.

input.entrypoints

entrypoints?: Record<string, string>;

Named files from client bundled for matching HTML template placeholders. The default is no named entrypoints. app, head, and body are reserved.

input.modules

modules?: Module[];

Extension modules initialized in array order. The default is []; module names must be unique. See the Module API.

Returned application facade

The returned instance preserves the inferred environment, localization and migration database types. Prefer importing your configured instance; use AppFacade for annotations and helper signatures when appropriate. For a configured facade, typeof configured retains the inferred types; explicit AppFacade<P, I, D> type arguments can describe a helper's expected environment, localization and migration database.

AppFacade

declare class AppFacade<
  T extends EnvSchema = EnvSchema,
  I extends I18NConfig | undefined = undefined,
  D extends DB = DB,
> {
  get i18n(): I18NRuntime<I>;
  config<P extends string>(path: P): ConfigValue<P>;
  migrate(value: MigrationDeclaration<D>): MigrationDeclaration<D>;
  env<K extends keyof T>(key: K): T[K]["infer"];
  get views(): ViewBag;
  get root(): FileRef;
  get log(): AppLogger;
}

ConfigValue, ViewBag, and AppLogger are readable representations of inferred supporting contracts; they are not exports from primate/app. The constructor and framework attachment symbols are internal and are omitted.

app.i18n

get i18n(): I18NRuntime<I>;

Localization facade inferred from input.i18n. This is the only facade member available in browser builds. Without i18n configuration, accessing localization operations uses the missing-i18n behavior. See the primate/i18n API and Internationalization guide.

app.config()

config<P extends string>(path: P): ConfigValue<P>;

Reads the parsed configuration through a dot-separated path. TypeScript infers the result for valid paths, including applied defaults. This method is server-only and throws when called from a browser build.

import app from "@/config/app";

const port = app.config("http.port"); // number

app.migrate()

migrate(
  value: MigrationDeclaration<D>,
): MigrationDeclaration<D>;

Validates and normalizes an application migration declaration while preserving the configured migration database type. It requires an eight-character lowercase hexadecimal id, unique valid parent IDs, and an optional function run. Invalid declarations throw migration diagnostics. This method is server-only and throws in browser builds.

MigrationDeclaration

Supporting input/output type for app.migrate().

type MigrationDeclaration<D extends DB = DB> = {
  id: string;
  parents: readonly string[];
  run?: (db: D) => MaybePromise<unknown>;
};

app.env()

env<K extends keyof T>(key: K): T[K]["infer"];

With env.schema, returns the parsed value for a declared key and throws when the key is missing from the parsed environment. Without a schema, it reads the named environment value as unknown. Invalid schema input fails when the server facade is attached. env() is server-only and throws in browser builds.

app.views

get views(): ViewBag;

The server's loaded view registry. It becomes available after the application facade is attached to the serving app; access before that point throws. This property is not available in browser builds.

const render = app.views.get<
  (props: { title: string }) => string | Promise<string>
>("docs/home/index.md");

ViewBag

Framework-owned supporting shape returned by app.views. It is not exported from primate/app.

type ViewBag = {
  get<T>(name: string): T;
  try(name: string): unknown | undefined;
  has(name: string): boolean;
  keys(): string[];
  values(): unknown[];
  entries(): [string, unknown][];
};

get() resolves registered frontend extensions and throws when no view exists. try() returns undefined instead. The collection methods return snapshots of the current registry.

app.root

get root(): FileRef;

Project-root filesystem reference from @rcompat/fs. It becomes available after server attachment and throws when used too early. In browser builds the getter always throws.

app.log

get log(): AppLogger;

Application logger attached to the serving app. It throws before server attachment and in browser builds.

AppLogger

Supporting shape returned by app.log.

type AppLogger = {
  readonly deprecations: readonly {
    deprecated: string;
    message: string;
    replacement: string;
  }[];
  readonly level: string;
  print(strings: TemplateStringsArray, ...params: unknown[]): void;
  system(strings: TemplateStringsArray, ...params: unknown[]): void;
  trace(strings: TemplateStringsArray, ...params: unknown[]): void;
  info(strings: TemplateStringsArray, ...params: unknown[]): void;
  warn(strings: TemplateStringsArray, ...params: unknown[]): void;
  deprecate(deprecated: string, replacement: string): void;
  error(error: unknown): void;
};

trace, info, and warn are tagged-template methods and notify registered module log hooks even when their level is below the console threshold. print and system write unclassified output. error() accepts an unknown thrown value.

deprecate() reports that an API was actually used and names its supported replacement. It emits every time it is called, regardless of the configured log level. Calls made while building are also retained as build diagnostics for strict-build handling; runtime calls remain warnings and never become failures. The deprecations snapshot contains only diagnostics attributed to the active build. Deprecation log hooks receive the "deprecation" level.

Browser availability

The browser-conditioned AppFacade keeps the typed i18n getter. config(), migrate(), env(), root, and log throw explicit server-only errors; views is absent. Do not import server configuration or environment access into frontend code.

Previous
Overview
Next
Module