Menu

API Reference

View as Markdown

@kovojs/server

Generated from 34 public subpaths — 489 exports, 489 documented. Do not edit by hand.

@kovojs/server#

Task: The ordinary app declaration surface: schemas, access, routes, queries, mutations, responses, and document structure.

Source: packages/server/src/index.ts

Values#

defineKovo#

Declare one app context without evaluating any live provider. Provider invocation begins only inside the returned contract's one assemble() call (SPEC §6.2.1/§9.5).

Signature

ts
function defineKovo<
  DbValue,
  RawRequest extends globalThis.Request = globalThis.Request,
  const AuthProvider extends SessionProvider<RawRequest, unknown> | undefined = undefined,
  const EnvSchema extends Schema<Record<string, unknown>> | undefined = undefined,
  Request = RawRequest &
    ([InferKovoSession<AuthProvider>] extends [never]
      ? object
      : { session: InferKovoSession<AuthProvider> | null }) & { db: DbValue } & {
      env: Readonly<InferKovoEnv<EnvSchema>>;
    },
  const Owner extends string | undefined = undefined,
>(
  options: DefineKovoInput<
    RawRequest,
    AuthProvider,
    DbValue,
    (
      request: RawRequest &
        ([InferKovoSession<AuthProvider>] extends [never]
          ? object
          : { session: InferKovoSession<AuthProvider> | null }) & {
          env: Readonly<InferKovoEnv<EnvSchema>>;
        },
    ) => Promise<DbValue>,
    EnvSchema,
    Request,
    Owner
  >,
): DefinedKovoContract<RawRequest, AuthProvider, DbValue, EnvSchema, Request, Owner>;
function defineKovo<
  DbValue,
  RawRequest extends globalThis.Request = globalThis.Request,
  const AuthProvider extends SessionProvider<RawRequest, unknown> | undefined = undefined,
  const EnvSchema extends Schema<Record<string, unknown>> | undefined = undefined,
  Request = RawRequest &
    ([InferKovoSession<AuthProvider>] extends [never]
      ? object
      : { session: InferKovoSession<AuthProvider> | null }) & { db: DbValue } & {
      env: Readonly<InferKovoEnv<EnvSchema>>;
    },
  const Owner extends string | undefined = undefined,
>(
  options: DefineKovoInput<
    RawRequest,
    AuthProvider,
    DbValue,
    (
      request: RawRequest &
        ([InferKovoSession<AuthProvider>] extends [never]
          ? object
          : { session: InferKovoSession<AuthProvider> | null }) & {
          env: Readonly<InferKovoEnv<EnvSchema>>;
        },
    ) => DbValue,
    EnvSchema,
    Request,
    Owner
  >,
): DefinedKovoContract<RawRequest, AuthProvider, DbValue, EnvSchema, Request, Owner>;
function defineKovo<
  DbValue,
  RawRequest extends globalThis.Request = globalThis.Request,
  const AuthProvider extends SessionProvider<RawRequest, unknown> | undefined = undefined,
  const EnvSchema extends Schema<Record<string, unknown>> | undefined = undefined,
  Request = RawRequest &
    ([InferKovoSession<AuthProvider>] extends [never]
      ? object
      : { session: InferKovoSession<AuthProvider> | null }) & { db: DbValue } & {
      env: Readonly<InferKovoEnv<EnvSchema>>;
    },
  const Owner extends string | undefined = undefined,
>(
  options: DefineKovoInput<
    RawRequest,
    AuthProvider,
    DbValue,
    AppDbProvider<DbValue>,
    EnvSchema,
    Request,
    Owner
  >,
): DefinedKovoContract<RawRequest, AuthProvider, DbValue, EnvSchema, Request, Owner>;
function defineKovo<
  RawRequest extends globalThis.Request = globalThis.Request,
  const AuthProvider extends SessionProvider<RawRequest, unknown> | undefined = undefined,
  const EnvSchema extends Schema<Record<string, unknown>> | undefined = undefined,
  Request = RawRequest &
    ([InferKovoSession<AuthProvider>] extends [never]
      ? object
      : { session: InferKovoSession<AuthProvider> | null }) & {
      env: Readonly<InferKovoEnv<EnvSchema>>;
    },
  const Owner extends string | undefined = undefined,
>(
  options: DefineKovoInput<RawRequest, AuthProvider, never, undefined, EnvSchema, Request, Owner>,
): DefinedKovoContract<RawRequest, AuthProvider, never, EnvSchema, Request, Owner>;

publicAccess#

Declare that a surface is intentionally public, with the audit reason attached.

Signature

ts
function publicAccess(reason: string): PublicAccess;

verifiedAccess#

Declare that a machine endpoint is covered by its verifier/auth scheme.

Signature

ts
const verifiedAccess: VerifiedMachineAccess = markStructuredAccessDecision(
  witnessFreeze({
    kind: 'verified-machine-auth',
  }),
);

domain#

Declare an invalidation domain — the currency the framework uses to connect writes to reads. A query's reads and a mutation's touches are lists of domains; touching a domain reruns every query that reads it (SPEC §10.1).

With no argument, the compiler derives the domain's stable name from the exported binding plus module path (SPEC §4.1). Runtime-only execution cannot prove that source identity, so generated registries must replace the internal placeholder before the domain is used as invalidation currency.

Parameter Type Description
key Optional explicit stable name for shared external vocabulary.
(returns) Domain<string> A Domain keyed by key.

Copyable example

ts
import { domain } from '@kovojs/server';

export const cart = domain();
export const product = domain('product');

Signature

ts
function domain(): Domain<string>;
function domain<const Key extends string>(key: Key): Domain<Key>;

tag#

Declare an invalidation tag — a Domain by another name, used for narrower, row-level invalidation keys alongside coarse domains (SPEC §10.1).

With no argument, the compiler derives the tag's stable name from the exported binding plus module path (SPEC §4.1).

Parameter Type Description
key Optional explicit stable name for shared external vocabulary.
(returns) Domain<string> A Tag keyed by key.

Copyable example

ts
import { tag } from '@kovojs/server';

export const cartItem = tag('cart-item');

Signature

ts
function tag(): Domain<string>;
function tag<const Key extends string>(key: Key): Domain<Key>;

s#

The schema builder. Compose validators with s.object, s.string, s.number, s.decimal, s.date, s.datetime, s.json, s.boolean, s.array, s.nullable, and s.file; each returns a Schema whose parse coerces and validates FormData-shaped input, so the same schema validates JSON and form submissions (SPEC §6.3).

Copyable example

ts
import { s } from '@kovojs/server';

const input = s.object({
  productId: s.string(),
  quantity: s.number().int().min(1).default(1),
  tags: s.array(s.string()),
});

const parsed = input.parse({ productId: 'p1', quantity: '2', tags: 'a' });
// parsed.quantity === 2, parsed.tags === ['a']

Signature

ts
const s = witnessFreeze({
  array<Item>(item: Schema<Item>): Schema<Item[]> {
    const closedItem = snapshotSchemaForRuntime(item, 's.array(item)');
    // `parseAsync` mirrors `s.object` (SPEC §6): each item flows through
    // `parseSchemaAsync` so a storing item schema (`s.file().store()`) runs its
    // async `storage.put`/`normalizeStorageKey` path. Without it, the runtime's
    // async input parse (`parseSchemaAsync`) would fall back to the sync `parse`
    // below, which for a storing file schema fabricates a result with no upload
    // and no key normalization (data loss + traversal-key passthrough; Part 4 M1).
    const schema: AsyncSchema<Item[]> = {
      parse(input: unknown): Item[] {
        const values = arrayValues(input);
        const output: Item[] = [];
        for (let index = 0; index < values.length; index += 1) {
          try {
            witnessDefineProperty(output, index, {
              configurable: true,
              enumerable: true,
              value: closedItem.parse(values[index]),
              writable: true,
            });
          } catch (error) {
            throw validationErrorFrom(error, [securityString(index)]);
          }
        }
        return output;
      },
      async parseAsync(input: unknown): Promise<Item[]> {
        const output: Item[] = [];

        const values = arrayValues(input);
        for (let index = 0; index < values.length; index += 1) {
          try {
            witnessDefineProperty(output, index, {
              configurable: true,
              enumerable: true,
              value: await parseSchemaAsync(closedItem, values[index], true),
              writable: true,
            });
          } catch (error) {
            throw validationErrorFrom(error, [securityString(index)]);
          }
        }

        return output;
      },
    };
    witnessWeakMapSet(schemaMetadata, schema, {
      item: closedItem as Schema<unknown>,
      kind: 'array',
    });
    return witnessFreeze(schema);
  },
  boolean(): Schema<boolean> {
    return witnessFreeze({
      parse(input: unknown): boolean {
        input = revealSchemaInput(input);
        if (typeof input === 'boolean') return input;
        if (input === undefined || input === null || input === '') return false;
        if (typeof input === 'number' && (input === 0 || input === 1)) return input === 1;

        if (typeof input === 'string') {
          const value = securityStringToLowerCase(input);
          if (value === '1' || value === 'on' || value === 'true' || value === 'yes') return true;
          if (value === '0' || value === 'false' || value === 'no' || value === 'off') return false;
        }

        throw validationError('Expected boolean');
      },
    });
  },
  date(): DateSchema {
    return new DateSchemaImpl('date');
  },
  datetime(): DateSchema {
    return new DateSchemaImpl('datetime');
  },
  decimal(options: DecimalSchemaOptions = {}): DecimalSchema {
    return new DecimalSchemaImpl(options);
  },
  file(options: FileSchemaOptions = {}): FileSchema {
    return new FileSchemaImpl(options);
  },
  json<Value extends JsonValue = JsonValue>(): Schema<Value> {
    return witnessFreeze({
      parse(input: unknown): Value {
        input = revealSchemaInput(input);
        const value = typeof input === 'string' ? parseJsonInput(input) : input;
        try {
          // SPEC §9.1.1: validate and commit the same exact JSON descriptors so an app-owned
          // Proxy cannot substitute different authority after schema validation.
          return assertAndCloneJsonValue(value, { root: 'JSON input' }) as Value;
        } catch {
          throw validationError('Expected JSON value');
        }
      },
    });
  },
  string(): StringSchema {
    return new StringSchemaImpl();
  },
  number(): NumberSchema {
    return new NumberSchemaImpl();
  },
  nullable<Value>(item: Schema<Value>): Schema<Value | null> {
    const closedItem = snapshotSchemaForRuntime(item, 's.nullable(item)');
    const schema: AsyncSchema<Value | null> = {
      parse(input: unknown): Value | null {
        input = revealSchemaInput(input);
        return input === null ? null : closedItem.parse(input);
      },
      async parseAsync(input: unknown): Promise<Value | null> {
        input = revealSchemaInput(input);
        return input === null ? null : await parseSchemaAsync(closedItem, input, true);
      },
    };
    witnessWeakMapSet(schemaMetadata, schema, {
      item: closedItem as Schema<unknown>,
      kind: 'nullable',
    });
    return witnessFreeze(schema);
  },
  secret<Value>(schema: Schema<Value>): Schema<SecretValue<Value>> {
    const closedSchema = snapshotSchemaForRuntime(schema, 's.secret(schema)');
    return witnessFreeze({
      parse(input: unknown): SecretValue<Value> {
        input = revealSchemaInput(input);
        return secret(closedSchema.parse(input));
      },
      async parseAsync(input: unknown): Promise<SecretValue<Value>> {
        input = revealSchemaInput(input);
        return secret(await parseSchemaAsync(closedSchema, input, true));
      },
    });
  },
  object<const Shape extends Record<string, Schema<unknown>>>(
    shape: Shape,
  ): Schema<{ [Key in keyof Shape]: InferSchema<Shape[Key]> }> {
    const closedShape = snapshotSchemaShape(shape);
    const schema: AsyncSchema<{ [Key in keyof Shape]: InferSchema<Shape[Key]> }> = {
      parse(input: unknown): { [Key in keyof Shape]: InferSchema<Shape[Key]> } {
        const record = formLikeToRecord(input);
        const output: Partial<{ [Key in keyof Shape]: InferSchema<Shape[Key]> }> = {};

        const keys = witnessObjectKeys(closedShape);
        for (let index = 0; index < keys.length; index += 1) {
          const key = keys[index] as keyof Shape;
          const fieldSchema = closedShape[key]!;
          try {
            const field = readOwnInputFieldSnapshot(record, securityString(key));
            const parsed = fieldSchema.parse(field.value) as InferSchema<Shape[keyof Shape]>;
            // SPEC §6/§9.4: an absent optional field is absent from schema-shaped JSON; an
            // explicitly present `undefined` remains observable and is refused by the wire sink.
            // Defaults still materialize because their parsed value is not `undefined`.
            if (!field.present && parsed === undefined) continue;
            witnessDefineProperty(output, key, {
              configurable: true,
              enumerable: true,
              value: parsed,
              writable: true,
            });
          } catch (error) {
            throw validationErrorFrom(error, [securityString(key)]);
          }
        }

        return output as { [Key in keyof Shape]: InferSchema<Shape[Key]> };
      },
      async parseAsync(input: unknown): Promise<{ [Key in keyof Shape]: InferSchema<Shape[Key]> }> {
        const record = formLikeToRecord(input);
        const output: Partial<{ [Key in keyof Shape]: InferSchema<Shape[Key]> }> = {};

        const keys = witnessObjectKeys(closedShape);
        for (let index = 0; index < keys.length; index += 1) {
          const key = keys[index] as keyof Shape;
          const fieldSchema = closedShape[key]!;
          try {
            const field = readOwnInputFieldSnapshot(record, securityString(key));
            const parsed = (await parseSchemaAsync(fieldSchema, field.value, true)) as InferSchema<
              Shape[keyof Shape]
            >;
            if (!field.present && parsed === undefined) continue;
            witnessDefineProperty(output, key, {
              configurable: true,
              enumerable: true,
              value: parsed,
              writable: true,
            });
          } catch (error) {
            throw validationErrorFrom(error, [securityString(key)]);
          }
        }

        return output as { [Key in keyof Shape]: InferSchema<Shape[Key]> };
      },
    };
    witnessWeakMapSet(schemaMetadata, schema, { kind: 'object', shape: closedShape });
    return witnessFreeze(schema);
  },
  record<Value>(value: Schema<Value>): Schema<Record<string, Value>> {
    const closedValue = snapshotSchemaForRuntime(value, 's.record(value)');
    const schema: AsyncSchema<Record<string, Value>> = {
      parse(input: unknown): Record<string, Value> {
        const record = recordInput(input);
        const output = requestCreateNullRecord<Value>() as Record<string, Value>;

        const keys = witnessObjectKeys(record);
        for (let index = 0; index < keys.length; index += 1) {
          const key = keys[index]!;
          const field = readOwnInputField(record, key);
          assertSafeRecordKey(key);
          try {
            output[key] = closedValue.parse(field);
          } catch (error) {
            throw validationErrorFrom(error, [key]);
          }
        }

        return output;
      },
      async parseAsync(input: unknown): Promise<Record<string, Value>> {
        const record = recordInput(input);
        const output = requestCreateNullRecord<Value>() as Record<string, Value>;

        const keys = witnessObjectKeys(record);
        for (let index = 0; index < keys.length; index += 1) {
          const key = keys[index]!;
          const field = readOwnInputField(record, key);
          assertSafeRecordKey(key);
          try {
            output[key] = await parseSchemaAsync(closedValue, field, true);
          } catch (error) {
            throw validationErrorFrom(error, [key]);
          }
        }

        return output;
      },
    };
    witnessWeakMapSet(schemaMetadata, schema, {
      kind: 'record',
      value: closedValue as Schema<unknown>,
    });
    return witnessFreeze(schema);
  },
});

errorBoundary#

Attach an error-boundary renderer to a fragment renderer, so a fragment that throws while rendering degrades to boundary HTML instead of failing the whole mutation response (SPEC §9.1).

Parameter Type Description
renderer Renderer The fragment renderer to wrap.
boundary { render( error: unknown, input: unknown, ): Promise<ServerFragmentRenderable> | ServerFragmentRenderable; target?: str… The renderer invoked when renderer throws.
(returns) Renderer & { errorBoundary: { render( error: unknown, input: unknown, ): Promise<ServerFragmentRenderable> | ServerFrag… The fragment renderer with an errorBoundary attached.

Signature

ts
function errorBoundary<
  Renderer extends {
    errorBoundary?: {
      render(
        error: unknown,
        input: unknown,
      ): Promise<ServerFragmentRenderable> | ServerFragmentRenderable;
      target?: string;
    };
    mode?: 'append' | 'prepend' | 'replace';
    render(input: unknown): Promise<ServerFragmentRenderable> | ServerFragmentRenderable;
    stylesheets?: readonly import('../hints.js').StylesheetAsset[];
    target: string;
    updateCoverage?: 'fragment' | 'plan';
  },
>(
  renderer: Renderer,
  boundary: {
    render(
      error: unknown,
      input: unknown,
    ): Promise<ServerFragmentRenderable> | ServerFragmentRenderable;
    target?: string;
  },
): Renderer & {
  errorBoundary: {
    render(
      error: unknown,
      input: unknown,
    ): Promise<ServerFragmentRenderable> | ServerFragmentRenderable;
    target?: string;
  };
};

mutation#

Declare a typed write. App-authored mutations use object form and the compiler derives the stable registry key from the exported binding plus module path (SPEC §4.1/§10.3). A mutation couples an input Schema, a handler that performs the write, optional typed errors, an optional guard, an optional static defaultRedirectTo, and an optional transaction wrapper. The input schema doubles as FormData coercion; context.fail(code, payload) returns a typed failure; context.invalidate(domain) records what the write touched so dependent queries rerun. CSRF is default-on — supply csrf, or use the explicit { csrf: false, csrfJustification: '...' } machine-caller posture.

Parameter Type Description
definition Omit< MutationDefinition<string, InputSchema, Errors, Request, Value, GuardedRequest>, 'access' | 'csrf' | 'csrfJustifi… Input schema, handler, and optional errors/guard/transaction/csrf.
(returns) MutationDefinition<string, InputSchema, Errors, Request, Value, GuardedRequest> & MutationFormDefinition<string, Reques… A MutationDefinition that receives its stable key from compiler-emitted metadata.

Copyable example

ts
import { mutation, s } from '@kovojs/server';

interface CartRequest {
  db: { add(productId: string, quantity: number): void };
}

export const addToCart = mutation({
  csrf: false,
  csrfJustification: 'signed inventory client request',
  input: s.object({
    productId: s.string(),
    quantity: s.number().int().min(1).default(1),
  }),
  errors: {
    OUT_OF_STOCK: s.object({ available: s.number().int().min(0) }),
  },
  handler(input, request: CartRequest, context) {
    if (input.quantity > 10) return context.fail('OUT_OF_STOCK', { available: 10 });
    request.db.add(input.productId, input.quantity);
    return { productId: input.productId };
  },
});

Signature

ts
function mutation<
  InputSchema extends Schema<unknown>,
  Errors extends Record<string, Schema<unknown>> = Record<string, Schema<unknown>>,
  Request = unknown,
  Value = unknown,
  GuardedRequest extends Request = Request,
>(
  definition: Omit<
    MutationDefinition<string, InputSchema, Errors, Request, Value, GuardedRequest>,
    'access' | 'csrf' | 'csrfJustification' | 'guard' | 'key' | 'machineReplayPrincipal'
  > &
    (
      | { access: AccessDecision; guard?: never }
      | { access?: never; guard: Guard<Request, GuardedRequest> }
      | { access?: never; guard?: never }
    ) &
    (
      | {
          csrf?: CsrfOptions<Request>;
          csrfJustification?: never;
          machineReplayPrincipal?: never;
        }
      | {
          csrf: false;
          csrfJustification: string;
          machineReplayPrincipal?: (request: GuardedRequest) => string;
        }
    ),
): MutationDefinition<string, InputSchema, Errors, Request, Value, GuardedRequest> &
  MutationFormDefinition<string, Request>;
function mutation<
  const Key extends string,
  InputSchema extends Schema<unknown>,
  Errors extends Record<string, Schema<unknown>> = Record<string, Schema<unknown>>,
  Request = unknown,
  Value = unknown,
  GuardedRequest extends Request = Request,
>(
  key: Key,
  definition: Omit<
    MutationDefinition<Key, InputSchema, Errors, Request, Value, GuardedRequest>,
    'access' | 'csrf' | 'csrfJustification' | 'guard' | 'key' | 'machineReplayPrincipal'
  > &
    (
      | { access: AccessDecision; guard?: never }
      | { access?: never; guard: Guard<Request, GuardedRequest> }
      | { access?: never; guard?: never }
    ) &
    (
      | {
          csrf?: CsrfOptions<Request>;
          csrfJustification?: never;
          machineReplayPrincipal?: never;
        }
      | {
          csrf: false;
          csrfJustification: string;
          machineReplayPrincipal?: (request: GuardedRequest) => string;
        }
    ),
): MutationDefinition<Key, InputSchema, Errors, Request, Value, GuardedRequest> &
  MutationFormDefinition<Key, Request>;

mutationFormAttributes#

Render the no-JS/enhanced form attributes for a typed mutation value (SPEC §6.3). Component-authored <form mutation={...}> is still compiler lowered when submitted-form targets are needed; this helper keeps direct server-rendered templates from hard-coding /_m/* URLs.

Signature

ts
function mutationFormAttributes<const Key extends string, Request = unknown>(
  definition: MutationFormDefinition<Key, Request>,
): MutationFormAttributes<Key, Request>;

queue#

Declare a named client-side FIFO queue shared by one or more mutations (SPEC §10.4). Use queue: true for the common per-mutation queue derived from that mutation's own source identity; use queue('checkout') only when several mutations intentionally share one queue.

Signature

ts
function queue<const Name extends string>(
  name: Name,
): {
  readonly [mutationQueueValueBrand]: Name;
  readonly name: Name;
};

query#

Declare a typed read. App-authored queries use object form and the compiler derives the stable registry key from the exported binding plus module path (SPEC §4.1/§10.2). The read set is the entire invalidation declaration: when a mutation touches a domain in reads, this query reruns. Optional args validate inputs, output validates results, and version/instanceKey control caching identity.

Parameter Type Description
definition Definition & (Exclude< keyof Definition, keyof Omit<QueryDefinition<string, any, any, any>, 'key'> > extends never ? 'a… load, reads, and optional args/output/guard/version.
(returns) Definition extends { args: Schema<infer Input> } ? Omit<Definition, 'args'> & { args: Schema<Input> & { <Props extends … A query definition that receives its stable key from compiler-emitted metadata.

Copyable example

ts
import { domain, query } from '@kovojs/server';

export const product = domain();

export const productsQuery = query({
  load: () => ({ items: [] as { id: string }[] }),
  reads: [product],
});

Signature

ts
function query<const Definition extends Omit<QueryDefinition<string, any, any, any>, 'key'>>(
  definition: Definition &
    (Exclude<
      keyof Definition,
      keyof Omit<QueryDefinition<string, any, any, any>, 'key'>
    > extends never
      ? 'access' | 'guard' extends keyof Definition
        ? {
            readonly __kovoQueryAccessBoundary: 'query() cannot declare both access and guard; choose exactly one access decision';
          }
        : Definition extends { load?: (...args: any[]) => infer Result }
          ? Awaited<Result> extends JsonValue
            ? unknown
            : {
                readonly __kovoQueryJsonBoundary: 'query() load result must be JSON-serializable; annotate Drizzle json/jsonb columns with .$type<...>() or declare output: s.record(...)';
              }
          : unknown
      : {
          readonly __kovoQueryDefinitionBoundary: 'query() definition contains unsupported field(s)';
        }),
): Definition extends { args: Schema<infer Input> }
  ? Omit<Definition, 'args'> & {
      args: Schema<Input> & {
        <Props extends object = any>(
          mapper: (props: Props) => Input,
        ): {
          args: (props: Props) => Input;
          query: QueryDefinition<string, unknown, Input, unknown>;
          schema: Schema<Input>;
        };
      };
      key: string;
      reads: readonly Domain[];
    }
  : Definition & { key: string; reads: readonly Domain[] };
function query<
  const Key extends string,
  const Definition extends Omit<QueryDefinition<string, any, any, any>, 'key'>,
>(
  key: Key,
  definition: Definition &
    (Exclude<
      keyof Definition,
      keyof Omit<QueryDefinition<string, any, any, any>, 'key'>
    > extends never
      ? 'access' | 'guard' extends keyof Definition
        ? {
            readonly __kovoQueryAccessBoundary: 'query() cannot declare both access and guard; choose exactly one access decision';
          }
        : Definition extends { load?: (...args: any[]) => infer Result }
          ? Awaited<Result> extends JsonValue
            ? unknown
            : {
                readonly __kovoQueryJsonBoundary: 'query() load result must be JSON-serializable; annotate Drizzle json/jsonb columns with .$type<...>() or declare output: s.record(...)';
              }
          : unknown
      : {
          readonly __kovoQueryDefinitionBoundary: 'query() definition contains unsupported field(s)';
        }),
): Definition extends { args: Schema<infer Input> }
  ? Omit<Definition, 'args'> & {
      args: Schema<Input> & {
        <Props extends object = any>(
          mapper: (props: Props) => Input,
        ): {
          args: (props: Props) => Input;
          query: QueryDefinition<string, unknown, Input, unknown>;
          schema: Schema<Input>;
        };
      };
      key: Key;
      reads: readonly Domain[];
    }
  : Definition & { key: Key; reads: readonly Domain[] };

endpoint#

Declare a raw HTTP endpoint: a handler taking a Request and returning a Response, mounted at an exact path or a path prefix. Endpoints are the escape hatch for machine traffic (webhooks, APIs) that bypasses the page/query pipeline, so every declaration carries audit metadata: explicit method, endpoint-level reason, raw response posture, and a prefix mount justification when mount: 'prefix' is used. Unsafe methods are CSRF-default-on; the closed GET/HEAD/OPTIONS set is reader-only and browser-state-effect-free. Opt an unsafe method out with csrf: false plus a justification (SPEC §6.6 and §9.1).

Parameter Type Description
path Path The path the endpoint mounts at.
definition EndpointDefinition<Method, Mount, Db> The handler, method, audit metadata, optional mount, auth, and CSRF opt-out.
(returns) EndpointDeclaration<Path, Method, Mount, Db> An EndpointDeclaration.

Copyable example

ts
import { endpoint } from '@kovojs/server';

export const health = endpoint('/healthz', {
  method: 'GET',
  reason: 'read-only health probe',
  csrf: false,
  csrfJustification: 'read-only health probe',
  response: { appOwnedSafety: true, body: 'text', cache: 'no-store' },
  handler: () => new Response('ok'),
});

Signature

ts
function endpoint<
  const Path extends string,
  const Method extends EndpointMethod = EndpointMethod,
  const Mount extends EndpointMount = 'exact',
  Db = unknown,
>(
  path: Path,
  definition: EndpointDefinition<Method, Mount, Db>,
): EndpointDeclaration<Path, Method, Mount, Db>;

guard#

Construct a self-naming executable guard. SPEC §10 default-deny access decisions require the audited guard to be the guard that runs; this wrapper stores the audit name on the executable function itself instead of accepting a separate hand-written label.

Signature

ts
function guard<Request, RefinedRequest extends Request = Request>(
  name: string,
  fn: Guard<Request, RefinedRequest>,
): Guard<Request, RefinedRequest>;

guards#

Built-in guard factories for routes, queries, and mutations. guards.authed() requires a logged-in session (and refines the request type), guards.role(r) requires a role, guards.rateLimit(opts) throttles, and guards.all(...) composes guards left-to-right. Attach the result as a guard on a route, query, or mutation (SPEC §6.5).

Copyable example

ts
import { guards, route } from '@kovojs/server'
import { type SessionRequestLike } from '@kovojs/server/routing';

interface AppRequest extends SessionRequestLike {}

export const dashboard = route('/dashboard', {
  guard: guards.authed<AppRequest>(),
  page: () => <h1>Dashboard</h1>,
});

Signature

ts
const guards = witnessFreeze({
  all<Request, RefinedRequest extends Request = Request>(
    ...items: Guard<Request, RefinedRequest>[]
  ): Guard<Request, RefinedRequest> {
    const executable = executableGuardAccessDecision(items) as
      | readonly Guard<Request, RefinedRequest>[]
      | undefined;
    if (executable === undefined) {
      throw new TypeError('guards.all(...) requires one or more dense executable guards.');
    }
    const guard: Guard<Request, RefinedRequest> = async (request: Request) => {
      for (let index = 0; index < executable.length; index += 1) {
        const item = executable[index]!;
        const result = await item(request);
        // Propagate the first denial (intent object) or bare `false` as-is so the
        // §6.5 status mapping stays owned by the render path, not flattened here.
        if (result !== true) return result;
      }

      return true;
    };
    const auditFacts: GuardAuditFact[] = [];
    for (let index = 0; index < executable.length; index += 1) {
      const item = executable[index]!;
      const facts = explainGuard(item);
      if (facts.length === 0) {
        appendGuardAuditFact(auditFacts, {
          kind: 'opaque',
          name: stableGuardFunctionAuditName(item),
        });
        continue;
      }
      for (let factIndex = 0; factIndex < facts.length; factIndex += 1) {
        const descriptor = witnessGetOwnPropertyDescriptor(facts as object, factIndex);
        if (descriptor !== undefined && 'value' in descriptor) {
          appendGuardAuditFact(auditFacts, descriptor.value as GuardAuditFact);
        }
      }
    }
    return stampGuardAudit(guard, auditFacts);
  },
  authed<Request extends SessionRequestLike>(): Guard<Request, AuthenticatedRequest<Request>> {
    return stampGuardAudit(
      (request) =>
        requestPrincipalSnapshot(request).kind === 'proven' ? true : unauthenticatedGuardFailure(),
      [{ auth: 'session-user', kind: 'authed', name: 'authed' }],
    );
  },
  rateLimit<Request extends SessionRequestLike>(
    options: RateLimitOptions<Request>,
  ): Guard<Request> {
    const rateOptions = snapshotRateLimitOptions(options);
    assertRateLimitOptions(rateOptions);
    const counts = createWitnessMap<string, { count: number; resetAt: number }>();

    return stampGuardAudit(
      (request) => {
        const now = requestStateNow();
        evictExpiredRateLimits(counts, now);

        const windowMs = rateOptions.windowMs ?? defaultRateLimitWindowMs;
        if (rateOptions.max <= 0) return rateLimitFailure(now + windowMs, now);

        const key = rateLimitKey(request, rateOptions);
        const existing = witnessMapGet(counts, key);

        if (existing && existing.resetAt > now) {
          if (existing.count >= rateOptions.max) return rateLimitFailure(existing.resetAt, now);

          existing.count += 1;
          return true;
        }

        const maxKeys = rateOptions.maxKeys ?? defaultRateLimitMaxKeys;
        if (witnessMapSize(counts) >= maxKeys) {
          // SPEC §9.5: an over-budget request MUST receive 429. Evicting an active key here
          // reopened that key's window under attacker-controlled key churn. Refuse unseen keys
          // until the earliest active window expires; never trade security truth for admission.
          let earliestResetAt = now + windowMs;
          witnessMapForEach(counts, (record) => {
            if (record.resetAt < earliestResetAt) earliestResetAt = record.resetAt;
          });
          return rateLimitFailure(earliestResetAt, now);
        }

        witnessMapSet(counts, key, {
          count: 1,
          resetAt: now + windowMs,
        });
        return true;
      },
      [
        {
          kind: 'rateLimit',
          name: 'rateLimit',
          per: rateOptions.key ? 'custom' : (rateOptions.per ?? 'session'),
        },
      ],
    );
  },
  role<Request extends RoleSessionRequestLike>(role: string): Guard<Request> {
    const closedRole = snapshotAuditText(role, 'guards.role() role');
    const auditName = snapshotAuditText(`role:${closedRole}`, 'guards.role() audit name');
    return stampGuardAudit(
      (request) => {
        const principal = requestPrincipalSnapshot(request);
        if (principal.kind !== 'proven') {
          return unauthenticatedGuardFailure();
        }
        if (!roleListIncludes(principal.roles, closedRole)) return unauthorizedGuardFailure();
        markPassedRoleGuard(request, closedRole);
        return true;
      },
      [
        {
          auth: 'session-role',
          kind: 'role',
          name: auditName as `role:${string}`,
          principal: normalizePrincipalKeyAudit('session.user.roles'),
          role: closedRole,
        },
      ],
    );
  },
  /**
   * Proof-bearing ownership guard (SPEC §10.3). The second argument is the exact single-column
   * `kovo((columns) => ({ key: columns.id }))` identity from a compiler-generated direct-owner
   * Postgres table. Kovo performs
   * one fixed key/owner lookup through the same principal-scoped managed request DB that the
   * handler receives. SQLite, ownerVia, composite/custom keys, and arbitrary callbacks belong on
   * {@link unprovenOwns} and remain visibly unproven in authorization explain.
   */
  owns<Request extends SessionRequestLike, KeyedRequest extends Request = Request, Key = unknown>(
    keyOf: (request: KeyedRequest) => Key,
    keyColumn: FrameworkPostgresOwnerKeyColumn<Key>,
    audit?: OwnershipGuardAuditOptions,
  ): Guard<Request> {
    const column = snapshotFrameworkPostgresOwnerGuardColumn(keyColumn);
    return createOwnershipGuard(
      keyOf,
      (request, key, principal) =>
        evaluateFrameworkPostgresOwnerGuard(request, key, column, principal),
      audit,
      {
        ownerPolicy: column.ownerPolicy,
        staticProof: 'framework-derived-owner-column',
      },
      'guards.owns()',
    );
  },
  /**
   * Explicit escape for an intentionally app-authored ownership predicate. This is the former
   * `guards.owns(keyOf, ownsRow, audit?)` callback behavior under a name that cannot be mistaken for
   * framework-derived guard/RLS correspondence. A pinned justification is mandatory, and explain
   * output always retains it beside `staticProof: 'not-claimed'`.
   */
  unprovenOwns<
    Request extends SessionRequestLike,
    KeyedRequest extends Request = Request,
    Key = unknown,
  >(
    keyOf: (request: KeyedRequest) => Key,
    ownsRow: (request: KeyedRequest, key: Key) => boolean | Promise<boolean>,
    audit: UnprovenOwnershipGuardAuditOptions,
  ): Guard<Request> {
    const justification = snapshotUnprovenOwnershipJustification(audit);
    return createOwnershipGuard(
      keyOf,
      (request, key) => ownsRow(request, key),
      audit,
      { justification, staticProof: 'not-claimed' },
      'guards.unprovenOwns()',
    );
  },
});

session#

Declare the session schema for the app: how to parse the raw session into a typed value, and how to wire a provider that resolves the session from a request. The parsed type flows into guards and request types (SPEC §6.5).

Parameter Type Description
schema Schema<Value> A Schema describing the session shape.
(returns) SessionDefinition<Value> A SessionDefinition with parse, provider, and the schema.

Copyable example

ts
import { s, session } from '@kovojs/server';

export const appSession = session(
  s.object({ userId: s.string() }),
);

Signature

ts
function session<Value>(schema: Schema<Value>): SessionDefinition<Value>;

layout#

Declare a reusable nested layout segment. Layouts compose page chrome around a route page; parent layouts wrap child layouts, guards run before the route page, and layout queries load from the same request lifecycle context as route/component queries (SPEC §4.5/§9.5).

Signature

ts
function layout<
  Request = unknown,
  const Queries extends Readonly<Record<string, QueryDefinition<string, any, any, Request>>> =
    Readonly<Record<string, QueryDefinition<string, any, any, Request>>>,
  Page extends LayoutRenderResult = LayoutRenderResult,
  Regions extends LayoutRegionResults = LayoutRegionResults,
>(
  definition: Omit<LayoutDefinition<Request, Queries, Page, Regions>, 'access' | 'guard'> &
    (
      | { access: AccessDecision; guard?: never }
      | { access?: never; guard: Guard<Request> }
      | { access?: never; guard?: never }
    ),
): LayoutDeclaration<Request, Queries, Page, Regions>;

notFound#

Return a 404 not-found outcome from a route page handler.

Parameter Type Description
(returns) NotFound A NotFound marker ({ notFound: true, status: 404 }).

Copyable example

ts
import { notFound } from '@kovojs/server';

const missing = notFound();
// missing.status === 404

Signature

ts
function notFound(): NotFound;

route#

Declare a server route with a page handler. The path's :params and any search schema are parsed and passed to page as a typed context; page returns the page value (rendered by renderRoutePageResponse), notFound(), or a response outcome. Optional guard/onUnauthenticated gate access, and meta/hint fields control the document head (SPEC §6.4). Pages are complete server-rendered documents — there is no client router.

Parameter Type Description
path Path URL pattern; :name segments become typed params.
definition Omit< RouteDefinition<Path, ParamsSchema, SearchSchema, Request, Page, GuardedRequest, Regions>, 'access' | 'guard' > &… The page handler plus optional params/search schemas, guards, and meta.
(returns) RouteDeclaration<Path, ParamsSchema, SearchSchema, Request, Page, GuardedRequest> A RouteDeclaration carrying path.

Copyable example

ts
import { notFound, route, s } from '@kovojs/server'
import { trustedHtml } from '@kovojs/browser';

const catalog = new Map<string, { name: string }>();

export const productRoute = route('/products/:id', {
  params: s.object({ id: s.string() }),
  page({ params }) {
    const product = catalog.get(params.id);
    if (!product) return notFound();
    return trustedHtml(`<h1>${product.name}</h1>`, {
      reason: 'catalog names are escaped by the reviewed route renderer',
      source: 'routes/product.ts',
    });
  },
});

Signature

ts
function route<
  const Path extends string,
  const ParamsSchema extends Schema<Record<string, string>> | undefined = undefined,
  const SearchSchema extends Schema<Record<string, RouteSearchValue>> | undefined = undefined,
  Request = unknown,
  Page extends RoutePageResult = RoutePageResult,
  GuardedRequest extends Request = Request,
  Regions extends RouteRegionDefinitions<any, GuardedRequest, Page> = RouteRegionDefinitions<
    any,
    GuardedRequest,
    Page
  >,
>(
  path: Path,
  definition: Omit<
    RouteDefinition<Path, ParamsSchema, SearchSchema, Request, Page, GuardedRequest, Regions>,
    'access' | 'guard'
  > &
    (
      | { access: AccessDecision; guard?: never }
      | { access?: never; guard: Guard<Request, GuardedRequest> }
      | { access?: never; guard?: never }
    ) = {},
): RouteDeclaration<Path, ParamsSchema, SearchSchema, Request, Page, GuardedRequest>;

respond#

Build a non-document route response from a route page handler: respond.file for an attachment download, respond.stream for a streamed body. Both set the content type and disposition; return the result instead of a page value (SPEC §6.4).

Copyable example

ts
import { respond, route } from '@kovojs/server';

export const exportRoute = route('/download/report.txt', {
  page: () =>
    respond.file('plain report\n', {
      contentType: 'text/plain; charset=utf-8',
      filename: 'report.txt',
    }),
});

Signature

ts
const respond = witnessFreeze({
  file<Headers extends Record<string, string> = Record<string, string>>(
    body: Exclude<RouteResponseBody, ReadableStream<Uint8Array>>,
    options: RouteFileOptions<Headers>,
  ) {
    return routeResponseOutcome(body, options, 'attachment');
  },
  /**
   * Serve a stored upload by its server-generated, runtime-opaque `ScopedKey`. KV428/KV450
   * (SPEC §6.6/§9.1): the key retains owner provenance while the bytes' inline-safety brand
   * degrades to a RUNTIME SIDECAR-MARKER, fail-closed:
   *
   *  - Defaults to `Content-Disposition: attachment` + `X-Content-Type-Options: nosniff`.
   *  - The served `Content-Type` is minted from the SNIFFED stored bytes (server truth), NOT the
   *    stored `contentType` (which a prior `accept.unverified()` may have set to a client lie).
   *  - `disposition: 'inline'` deep-sniffs and REFUSES to serve unless the bytes are known-passive
   *    (the runtime sidecar-marker refuse-to-serve-inline-if-unverified floor).
   *
   * @param storage - The storage capability to read from.
   * @param key - The opaque stored object key (from `s.file().store(...)`).
   */
  async storedFile(
    storage: StorageReadCapability,
    key: ScopedKey,
    options: RouteStoredFileOptions = {},
  ) {
    const keyFacts = scopedKeyFactsFor(key);
    const storedDisposition = stableOwnDataValue(options, 'disposition');
    const storedFilename = stableOwnDataValue(options, 'filename');
    if (
      storedDisposition !== undefined &&
      storedDisposition !== 'attachment' &&
      storedDisposition !== 'inline'
    ) {
      throw new TypeError('respond.storedFile() disposition must be attachment or inline.');
    }
    if (storedFilename !== undefined && typeof storedFilename !== 'string') {
      throw new TypeError('respond.storedFile() filename must be a string.');
    }
    if ((typeof storage !== 'object' && typeof storage !== 'function') || storage === null) {
      throw new TypeError('respond.storedFile() storage must be a stable read capability.');
    }
    const get = stableRequiredOwnDataValue(storage, 'get');
    if (typeof get !== 'function') {
      throw new TypeError('respond.storedFile() storage.get must be an own data function.');
    }
    const object = await witnessReflectApply<unknown>(get, storage, [key]);
    if (object === undefined) return undefined;
    if (typeof object !== 'object' || object === null || securityArrayIsArray(object)) {
      throw new TypeError('respond.storedFile() storage.get returned an invalid object.');
    }
    const body = stableRequiredOwnDataValue(object, 'body');
    const etag = stableOwnDataValue(object, 'etag');
    const metadata = stableOwnDataValue(object, 'metadata');
    if (!securityIsUint8Array(body)) {
      throw new TypeError('respond.storedFile() storage.get body must be Uint8Array bytes.');
    }
    if (etag !== undefined && typeof etag !== 'string') {
      throw new TypeError('respond.storedFile() storage.get etag must be a string.');
    }
    if (
      metadata !== undefined &&
      (typeof metadata !== 'object' || metadata === null || securityArrayIsArray(metadata))
    ) {
      throw new TypeError('respond.storedFile() storage.get metadata must be a stable record.');
    }
    const metadataFilename =
      metadata === undefined ? undefined : stableOwnDataValue(metadata, 'filename');
    if (metadataFilename !== undefined && typeof metadataFilename !== 'string') {
      throw new TypeError('respond.storedFile() storage filename metadata must be a string.');
    }
    const disposition = storedDisposition ?? 'attachment';
    const bodySnapshot = securityUint8ArraySlice(body);
    const sniffed = sniffUploadBytes(bodySnapshot);
    if (disposition === 'inline' && !sniffed.inlineSafe) {
      throw new InlineUnverifiedUploadError(
        `Refusing to serve stored object "${keyFacts.key}" inline: its sniffed content type is not a ` +
          'known-passive type. Serve as an attachment, or rasterize/re-encode the bytes.',
      );
    }
    const filename = storedFilename ?? metadataFilename;
    return routeResponseOutcome(bodySnapshot, {
      // Server truth: the served type is the SNIFFED type, never the stored (possibly-client) type.
      contentType: sniffed.contentType,
      disposition,
      ...(filename === undefined ? {} : { filename }),
      ...(etag === undefined ? {} : { etag }),
    });
  },
  stream<Headers extends Record<string, string> = Record<string, string>>(
    body: RouteResponseBody,
    options: RouteStreamOptions<Headers>,
  ) {
    const rawDisposition = stableOwnDataValue(options, 'disposition');
    const declaredContentType = stableOwnDataValue(options, 'contentType');
    const unsafeInlineReceipt = stableOwnDataValue(options, 'unsafeInline');
    if (
      rawDisposition !== undefined &&
      rawDisposition !== 'attachment' &&
      rawDisposition !== 'inline'
    ) {
      throw new TypeError('respond.stream() disposition must be attachment or inline.');
    }
    if (typeof declaredContentType !== 'string') {
      throw new TypeError('respond.stream() contentType must be a string.');
    }
    const unsafeInlineAccepted =
      unsafeInlineReceipt === undefined
        ? false
        : unsafeInlineAcceptanceSnapshot(unsafeInlineReceipt) === unsafeInlineReceipt;
    const disposition = rawDisposition ?? 'attachment';
    // KV428 (SPEC §6.6/§9.1): inline rendering is a branded opt-in over verified-safe bytes. For an
    // in-memory body we deep-sniff and refuse unless the bytes are a known-passive type; an
    // un-bufferable stream cannot be sniffed, so it requires the explicit `unsafeInline` receipt
    // (the framework re-encode/rasterize attestation). This is the fail-closed runtime floor — the
    // honest ceiling is "attacker bytes never render inline as active content", not an unspoofable
    // type. Authors override the sniffed contentType via `unsafeInline(...)` (audited risk).
    const bodySnapshot = snapshotRouteResponseBody(body);
    const contentType =
      disposition === 'inline'
        ? assertInlineBody(bodySnapshot, declaredContentType, unsafeInlineAccepted)
        : declaredContentType;
    return routeResponseOutcome(
      bodySnapshot,
      {
        contentType,
        etag: stableOwnDataValue(options, 'etag'),
        filename: stableOwnDataValue(options, 'filename'),
        headers: stableOwnDataValue(options, 'headers'),
      },
      disposition,
    );
  },
});

unsafeInline#

Accept the risk of bypassing Kovo's inline-body byte sniffer for bytes independently re-encoded or rasterized by the application (SPEC §6.6/§9.1). The required printable justification is surfaced by kovo explain capabilities; the returned receipt is opaque and runtime-authenticated.

Signature

ts
function unsafeInline(justification: string): UnsafeInlineAcceptance;

BodyAttrs#

Constrained attributes for the framework-owned <body> element.

Signature

ts
function BodyAttrs(props: DocumentShellAttributes & { children?: never }): unknown;

BodyEnd#

Contribution placed before the framework-owned </body> closer, including deferred streams.

Signature

ts
function BodyEnd(props: { children?: unknown }): unknown;

BodyStart#

Contribution placed immediately after the framework-owned <body> opener.

Signature

ts
function BodyStart(props: { children?: unknown }): unknown;

Document#

TSX declaration boundary for app-owned document contributions (SPEC.md §9.5).

Signature

ts
function Document(props: {
  children?: unknown;
  lang?: string;
  title?: string;
}): DocumentConfig;

FontPreload#

Font preload primitive with secure defaults.

Signature

ts
function FontPreload(props: {
  crossorigin?: boolean | string;
  href: string;
  type?: string;
}): unknown;

Document head contribution container (SPEC.md §9.5).

Signature

ts
function Head(props: { children?: unknown }): unknown;

HtmlAttrs#

Constrained attributes for the framework-owned <html> element.

Signature

ts
function HtmlAttrs(props: DocumentShellAttributes & { children?: never }): unknown;

InlineScript#

Inline script primitive that enrolls the emitted source in document CSP.

Signature

ts
function InlineScript(props: {
  children?: string | readonly string[] | TrustedHtml;
  id: string;
  run: 'afterInteractive' | 'beforePaint';
}): unknown;

InlineStyle#

Inline style primitive that enrolls the emitted source in document CSP.

Signature

ts
function InlineStyle(props: {
  children?: string | readonly string[] | TrustedHtml;
  id: string;
  source: string;
}): unknown;

Meta#

Structured <meta> document primitive.

Signature

ts
function Meta(props: {
  charset?: string;
  content?: string;
  name?: string;
  property?: string;
}): unknown;

ModulePreload#

Module preload primitive.

Signature

ts
function ModulePreload(props: { href: string; integrity?: string }): unknown;

StylesheetLink link primitive.

Signature

ts
function StylesheetLink(props: { href: string; media?: string }): unknown;

Defer#

Defer a route region until after the initial document shell with JSX-native fallback/rendering.

Inside normal route document rendering, deferred priorities return a framework-owned <kovo-defer> placeholder and record a fragment stream chunk that arrives later in the same document response. Outside that document context, including mutation fragment renders, this renders the full region immediately so refreshes remain complete (SPEC §8).

Signature

ts
function Defer(props: DeferProps): ServerRenderable;

i18n#

Declare a typed message catalog for one locale. Look messages up with t, which type-checks keys against this catalog. i18n stays server-rendered (plans/open-design-areas.md).

Parameter Type Description
locale string The catalog's locale tag (e.g. 'en').
messages Messages A map of message keys to template strings ({name} placeholders).
(returns) I18nCatalog<Messages> An I18nCatalog.

Copyable example

ts
import { i18n, t } from '@kovojs/server';

const en = i18n('en', { greeting: 'Hello, {name}!' });
const text: string = t(en, 'greeting', { name: 'Sam' });

Signature

ts
function i18n<const Messages extends Record<string, string>>(
  locale: string,
  messages: Messages,
): I18nCatalog<Messages>;

metaFromQuery#

Derive route metadata from a query's loaded value, so the document head reflects the same data the page rendered. Returns a deferred meta factory when given just a derive function, or resolved meta when given the value directly (SPEC §6.4).

Parameter Type Description
queryDefinition Query The query whose result drives the metadata.
derive (value: QueryResult<Query>) => Meta Maps the query's value to RouteMeta.
(returns) RouteMetaFactory A RouteMetaFactory (deferred) or resolved RouteMeta.

Signature

ts
function metaFromQuery<
  const Query extends QueryDefinition<string, unknown, any, any>,
  const Meta extends RouteMeta,
>(queryDefinition: Query, derive: (value: QueryResult<Query>) => Meta): RouteMetaFactory;
function metaFromQuery<
  const Query extends { load?: (input: never) => unknown },
  const Meta extends RouteMeta,
>(_query: Query, value: QueryResult<Query>, derive: (value: QueryResult<Query>) => Meta): Meta;

t#

Resolve a message from an i18n catalog, substituting {name} placeholders. The key is type-checked against the catalog's messages (plans/open-design-areas.md).

Parameter Type Description
catalog I18nCatalog<Messages> The catalog to read from.
key Key A message key present in the catalog.
values Record<string, string | number> Placeholder substitutions.
(returns) string The resolved, substituted message string.

Signature

ts
function t<
  Messages extends Record<string, string>,
  Key extends Extract<keyof Messages, string>,
>(catalog: I18nCatalog<Messages>, key: Key, values: Record<string, string | number> = {}): string;

safeRichHtml#

Sanitizes CMS/rich-text HTML with Kovo's conservative runtime floor and returns the explicit trusted-HTML brand accepted by server rendering sinks.

The sanitizer is runtime defense-in-depth (SPEC §6.6): it parses and drops executable markup, event handlers, javascript: URLs, and unsafe URL-bearing attributes before branding. It is not a by-construction XSS elimination claim.

Signature

ts
function safeRichHtml(value: string, options?: SafeRichHtmlOptions): TrustedHtml;

stylesheet#

Declare a local or external stylesheet for route/page hints.

Local paths derive /assets/<file> unless options.href overrides it; external and root-relative hrefs are preserved.

Signature

ts
function stylesheet(source: string, options?: StylesheetDeclarationOptions): StylesheetAsset;
function stylesheet(options: StylesheetDeclarationOptions): StylesheetAsset;

stream#

Build SPEC §9.1 streaming mutation wire chunks. Text chunks are escaped by the server renderer and are coalesced before being written to the response stream.

Signature

ts
const stream = {
  done(options: { reason?: string } = {}): MutationStreamDoneChunk {
    return { kind: 'done', ...(options.reason === undefined ? {} : { reason: options.reason }) };
  },
  fragment(options: {
    html: MutationStreamFragmentHtml;
    mode?: 'append' | 'replace';
    target: string;
  }): MutationStreamFragmentChunk {
    return {
      html: options.html,
      kind: 'fragment',
      ...(options.mode === undefined ? {} : { mode: options.mode }),
      target: options.target,
    };
  },
  query(options: {
    delta?: boolean;
    key?: string;
    name: string;
    value: unknown;
    version?: number | string;
  }): MutationStreamQueryChunk {
    return {
      ...(options.delta === undefined ? {} : { delta: options.delta }),
      ...(options.key === undefined ? {} : { key: options.key }),
      kind: 'query',
      name: options.name,
      value: options.value,
      ...(options.version === undefined ? {} : { version: options.version }),
    };
  },
  text(
    target: string,
    text: string,
    options: { mode?: 'append' | 'checkpoint' } = {},
  ): MutationStreamTextChunk {
    return {
      kind: 'text',
      ...(options.mode === undefined ? {} : { mode: options.mode }),
      target,
      text,
    };
  },
};

isCreateAppBootError#

Type guard for CreateAppBootError, surviving cross-realm/duplicate-module boundaries.

Signature

ts
function isCreateAppBootError(error: unknown): error is CreateAppBootError;

Supporting types#

AppAssemblyOptions#

Explicit declaration inventory consumed once by app.assemble().

Signature

ts
interface AppAssemblyOptions<Request, DbValue, Owner extends string | undefined> {
  endpoints?: readonly {
    readonly [appDeclarationHandleBrand]: {
      readonly kind: 'endpoint';
      readonly owner: Owner;
    };
  }[];
  layouts?: readonly {
    readonly [appDeclarationHandleBrand]: {
      readonly kind: 'layout';
      readonly owner: Owner;
    };
  }[];
  mutations?: readonly {
    readonly [appDeclarationHandleBrand]: {
      readonly kind: 'mutation';
      readonly owner: Owner;
    };
  }[];
  queries?: readonly {
    readonly [appDeclarationHandleBrand]: {
      readonly kind: 'query';
      readonly owner: Owner;
    };
  }[];
  routes?: readonly {
    readonly [appDeclarationHandleBrand]: {
      readonly kind: 'route';
      readonly owner: Owner;
    };
  }[];
  tasks?: readonly {
    readonly [appDeclarationHandleBrand]: {
      readonly kind: 'task';
      readonly owner: Owner;
    };
  }[];
}

AppEndpointFactory#

Endpoint factory with its managed DB context inferred from defineKovo({ db }).

Signature

ts
interface AppEndpointFactory<Db, Owner extends string | undefined> {
  /** Adopt one exact standalone declaration from an advanced endpoint capability subpath. */
  <
    const Path extends string,
    const Method extends EndpointMethod,
    const Mount extends EndpointMount,
    EndpointDb,
  >(
    declaration: EndpointDeclaration<Path, Method, Mount, EndpointDb>,
  ): EndpointHandle<Path, Owner>;
  <
    const Path extends string,
    const Method extends EndpointMethod = EndpointMethod,
    const Mount extends EndpointMount = 'exact',
  >(
    path: Path,
    definition: {
      access: AccessDecision;
      auth: EndpointAuthDeclaration;
      handler:
        | ((request: EndpointRequest) => Promise<Response> | Response)
        | ((
            request: EndpointRequest,
            context: EndpointDbContext<Db, Method>,
          ) => Promise<Response> | Response);
      method: Method;
      reason: string;
      response: EndpointResponsePosture;
    } & ({ db?: never } | { db: true }) &
      (Mount extends 'prefix'
        ? { mount: Mount; mountJustification: string }
        : { mount?: Mount; mountJustification?: never }) &
      ({ csrf?: true; csrfJustification?: never } | { csrf: false; csrfJustification: string }),
  ): EndpointHandle<Path, Owner>;
}

AppLayoutFactory#

Layout factory bound to the app read request.

Signature

ts
interface AppLayoutFactory<Request, Owner extends string | undefined> {
  <
    const Access extends AccessDecision | undefined = undefined,
    const Queries extends Readonly<
      Record<
        string,
        {
          readonly [appDeclarationHandleBrand]: {
            readonly kind: 'query';
            readonly owner: Owner;
          };
          readonly key: string;
        }
      >
    > = Readonly<Record<never, never>>,
    Page extends LayoutRenderResult = LayoutRenderResult,
    Regions extends LayoutRegionResults = LayoutRegionResults,
  >(definition: {
    access?: Exclude<Access, undefined>;
    bootstrapScript?: string;
    boundaries?: unknown;
    guard?: never;
    i18n?: unknown;
    meta?: unknown;
    modulepreloads?: readonly string[];
    parent?: {
      readonly [appDeclarationHandleBrand]: {
        readonly kind: 'layout';
        readonly owner: Owner;
      };
    };
    prefetch?: 'conservative' | 'moderate' | false;
    prefetchJustification?: string;
    prerenderUrls?: readonly string[];
    queries?: Queries;
    render?: (
      queries: {
        [Name in keyof Queries]: Queries[Name] extends QueryHandle<
          infer _Input,
          infer Value,
          infer _Owner
        >
          ? Awaited<Value>
          : unknown;
      },
      state: undefined,
      slots: {
        children: ComponentChild;
        regions: Regions;
        request: [Access] extends [undefined]
          ? Request
          : AppRequestForAccess<Request, Extract<Access, AccessDecision>>;
      },
    ) => Page | Promise<Page>;
    stylesheets?: readonly (string | StylesheetAsset)[];
  }): LayoutHandle<Owner>;
}

AppMutationFactory#

Mutation factory bound to one app request/session/DB/env contract.

Signature

ts
interface AppMutationFactory<Request, Owner extends string | undefined> {
  <
    InputSchema extends Schema<unknown>,
    Errors extends Record<string, Schema<unknown>> = Record<string, Schema<unknown>>,
    const Access extends AccessDecision = AccessDecision,
    Value = unknown,
  >(
    definition: {
      access: Access;
      defaultRedirectTo?: string;
      errors?: Errors;
      guard?: never;
      handler: (
        input: InferSchema<InputSchema>,
        request: MutationHandlerRequest<AppRequestForAccess<Request, Access>>,
        context: Parameters<
          MutationDefinition<
            string,
            InputSchema,
            Errors,
            MutationHandlerRequest<AppRequestForAccess<Request, Access>>,
            Value,
            MutationHandlerRequest<AppRequestForAccess<Request, Access>>
          >['handler']
        >[2],
      ) => Promise<Value | MutationFail> | Value | MutationFail;
      input: InputSchema;
      optimistic?: readonly {
        readonly [appOptimisticBindingBrand]: {
          readonly input: InferSchema<InputSchema>;
          readonly owner: Owner;
          readonly value: unknown;
        };
      }[];
      principalEpoch?: unknown;
      queue?: unknown;
      redirectTo?: unknown;
      registry?: {
        queries?: readonly { key: string }[];
        tables?: readonly string[];
        touches?: readonly Domain[];
      };
      stream?: unknown;
      transaction?: unknown;
    } & (
      | {
          csrf?: never;
          csrfJustification?: never;
          machineReplayPrincipal?: never;
        }
      | {
          csrf: false;
          csrfJustification: string;
          machineReplayPrincipal?: (
            request: MutationHandlerRequest<AppRequestForAccess<Request, Access>>,
          ) => string;
        }
    ),
  ): MutationHandle<InferSchema<InputSchema>, Value, Errors, Owner>;
}

AppQueryFactory#

Query factory bound to one app request/session/DB/env contract.

SPEC §6.2.1: callback parameters retain the complete provider-derived request, while the returned declaration handle projects only its public authoring facts. Threading the callback request into the exported handle would make downstream declaration emit expand private read-DB or task witnesses instead of naming the public handle interface.

Signature

ts
interface AppQueryFactory<Request, Owner extends string | undefined> {
  <
    const InputSchema extends Schema<unknown> | undefined = undefined,
    const Access extends AccessDecision = AccessDecision,
    Value extends JsonValue = JsonValue,
    const Definition extends object = object,
  >(
    definition: Definition & {
      access: Access;
      args?: InputSchema;
      delta?: readonly { domain: string; key: string; path: string }[];
      guard?: never;
      instanceKey?:
        | string
        | (InputSchema extends Schema<infer Input> ? (input: Input) => string | undefined : never);
      load?: (
        input: InputSchema extends Schema<infer Input> ? Input : undefined,
        context: Parameters<
          NonNullable<
            QueryDefinition<
              string,
              Value,
              InputSchema extends Schema<infer Input> ? Input : undefined,
              AppRequestForAccess<Request, Access>
            >['load']
          >
        >[1],
      ) => Promise<Value> | Value;
      output?: Schema<Value>;
      read?: QueryReadConfig;
      reads?: readonly Domain[];
      version?:
        | ((
            input: InputSchema extends Schema<infer Input> ? Input : undefined,
            value: Value,
          ) => number | string | undefined)
        | number
        | string;
    } & {
      [Field in Exclude<
        keyof Definition,
        | 'access'
        | 'args'
        | 'delta'
        | 'guard'
        | 'instanceKey'
        | 'load'
        | 'output'
        | 'read'
        | 'reads'
        | 'version'
      >]: never;
    },
  ): QueryHandle<InputSchema extends Schema<infer Input> ? Input : undefined, Value, Owner>;
}

AppRequestForAccess#

Preserve the framework-threaded read DB capability while applying executable guard refinements. A guard is allowed to narrow request/session facts; intersecting its raw request type back into AppReadRequest must not recover write methods that Reader<Db> deliberately removed (SPEC §6.2.1/§6.6/§10.2).

Signature

ts
type AppRequestForAccess<Base, Access> = Access extends readonly (infer Item)[]
  ? Item extends Guard<infer _GuardRequest, infer Refined>
    ? Base extends { db: infer ReadDb }
      ? Omit<Base & Refined, 'db'> & { db: ReadDb }
      : Base & Refined
    : Base
  : Base;

AppRouteFactory#

Route factory with params/search and lifecycle request inferred from the app contract.

Signature

ts
interface AppRouteFactory<Request, Owner extends string | undefined> {
  <
    const Path extends string,
    const ParamsSchema extends Schema<Record<string, string>> | undefined = undefined,
    const SearchSchema extends Schema<Record<string, RouteSearchValue>> | undefined = undefined,
    const Access extends AccessDecision = AccessDecision,
    Page extends RoutePageResult = RoutePageResult,
    Regions extends Readonly<
      Record<
        string,
        (
          context: {
            params: ParamsSchema extends Schema<infer Params> ? Params : Record<string, string>;
            path: Path;
            search: SearchSchema extends Schema<infer Search> ? Search : Record<string, JsonValue>;
          },
          request: AppRequestForAccess<Request, Access>,
        ) => Page | Promise<Page>
      >
    > = Readonly<Record<never, never>>,
  >(
    path: Path,
    definition: {
      access: Access;
      bootstrapScript?: string;
      boundaries?: unknown;
      guard?: never;
      i18n?: unknown;
      layout?: {
        readonly [appDeclarationHandleBrand]: {
          readonly kind: 'layout';
          readonly owner: Owner;
        };
      };
      meta?: unknown;
      modulepreloads?: readonly string[];
      onUnauthenticated?: unknown;
      page?: (
        context: {
          params: ParamsSchema extends Schema<infer Params> ? Params : Record<string, string>;
          path: Path;
          search: SearchSchema extends Schema<infer Search> ? Search : Record<string, JsonValue>;
          signUrl?: SignUrlContext['signUrl'];
        },
        request: AppRequestForAccess<Request, Access>,
      ) => Page | Promise<Page>;
      params?: ParamsSchema;
      prefetch?: 'conservative' | 'moderate' | false;
      prefetchJustification?: string;
      prerenderUrls?: readonly string[];
      regions?: Regions;
      search?: SearchSchema;
      staticPaths?: readonly string[];
      stylesheets?: readonly (string | StylesheetAsset)[];
    },
  ): RouteHandle<Path, Owner>;
}

AppTaskFactory#

Durable-task factory returning an app-owned named handle.

Signature

ts
interface AppTaskFactory<Owner extends string | undefined> {
  <InputSchema extends Schema<unknown>, Value = unknown>(definition: {
    catchUp?: 'skip' | 'backfill';
    concurrency?: number;
    cron?: string;
    cronArgs?: InferSchema<InputSchema>;
    input: InputSchema;
    maxGenerations?: number;
    priority?: number;
    retry?: {
      backoff?: 'exponential' | 'linear';
      maxAttempts?: number;
    };
    run(
      args: InferSchema<InputSchema>,
      context: import('./task.js').TaskRunContext,
    ): Promise<Value> | Value;
    timeoutMs?: number;
  }): TaskHandle<InferSchema<InputSchema>, Value, Owner>;
}

AuthenticatedAppRequest#

App request refined by the executable app.authenticated guard.

Signature

ts
type AuthenticatedAppRequest<Request> = Request extends {
  session: infer Session;
}
  ? Request & {
      session: NonNullable<Session> extends { user?: infer User }
        ? NonNullable<Session> & { user: NonNullable<User> }
        : NonNullable<Session>;
    }
  : Request;

DefineKovoInput#

Fully inferred input object accepted by defineKovo().

Signature

ts
type DefineKovoInput<
  RawRequest extends globalThis.Request,
  AuthProvider extends SessionProvider<RawRequest, unknown> | undefined,
  DbValue,
  DatabaseProvider,
  EnvSchema extends Schema<Record<string, unknown>> | undefined,
  Request,
  Owner extends string | undefined,
> = Omit<
  DefineKovoOptions<
    RawRequest,
    InferKovoSession<AuthProvider>,
    DbValue,
    InferKovoEnv<EnvSchema>,
    Request,
    Owner
  >,
  'auth' | 'db' | 'env'
> & {
  auth?: AuthProvider;
  db?: DatabaseProvider;
  env?: EnvSchema;
};

DefineKovoOptions#

Provider/config declarations captured inertly by defineKovo.

Signature

ts
interface DefineKovoOptions<
  RawRequest extends globalThis.Request,
  SessionValue,
  DbValue,
  EnvValue extends Record<string, unknown>,
  Request,
  Owner extends string | undefined,
> {
  appId?: Owner;
  auth?: SessionProvider<RawRequest, SessionValue>;
  clientModules?: VersionedClientModuleStore | VersionedClientModuleRegistry;
  csrf?: CsrfOptions<NoInfer<Request>>;
  db?:
    | ((
        request: RawRequest &
          ([SessionValue] extends [never] ? object : { session: SessionValue | null }) & {
            env: Readonly<EnvValue>;
          },
      ) => Promise<DbValue> | DbValue)
    | AppDbProvider<DbValue>;
  document?: AppDocumentOptions | DocumentDeclaration;
  egress?: AppEgressOptions;
  env?: Schema<EnvValue>;
  /** Explicit operator snapshot seam for tests and custom supported hosts. */
  envSource?: Record<string, unknown>;
  errorShells?: AppErrorShellOptions;
  mutationReplayStore?: MutationReplayStore;
  onError?: ServerErrorHandler;
  principalEpochStore?: PrincipalEpochStore;
  renderRoute?: (
    value: unknown,
    context: {
      params: Record<string, string>;
      request: Request;
      route: { path: string };
      search: unknown;
    },
  ) => Promise<string> | string;
  requestLimits?: AppRequestLimitOptions;
  stylesheets?: readonly (string | StylesheetAsset)[];
}

DefinedKovoContract#

App contract produced after provider/session/DB/env inference.

Signature

ts
type DefinedKovoContract<
  RawRequest extends globalThis.Request,
  AuthProvider extends SessionProvider<RawRequest, unknown> | undefined,
  DbValue,
  EnvSchema extends Schema<Record<string, unknown>> | undefined,
  Request,
  Owner extends string | undefined,
> = KovoContract<
  RawRequest,
  InferKovoSession<AuthProvider>,
  DbValue,
  InferKovoEnv<EnvSchema>,
  Request,
  Owner
>;

EndpointHandle#

Named app-scoped endpoint handle.

Signature

ts
interface EndpointHandle<
  Path extends string = string,
  Owner extends string | undefined = string | undefined,
> {
  readonly [appDeclarationHandleBrand]: {
    readonly kind: 'endpoint';
    readonly owner: Owner;
  };
  readonly path: Path;
}

InferKovoEnv#

Environment record inferred from defineKovo({ env: schema }).

Signature

ts
type InferKovoEnv<EnvSchema> =
  EnvSchema extends Schema<infer EnvValue>
    ? EnvValue extends Record<string, unknown>
      ? EnvValue
      : Record<never, never>
    : Record<never, never>;

InferKovoSession#

Session value inferred from a plain or cookie-forwarding defineKovo({ auth }) provider.

Signature

ts
type InferKovoSession<Provider> = Provider extends (...args: never[]) => infer Result
  ? Awaited<Result> extends infer Item
    ? Item extends null | undefined
      ? never
      : Item extends {
            readonly setCookies?: readonly string[];
            readonly value: infer Value;
          }
        ? NonNullable<Value>
        : Item
    : never
  : never;

KovoContract#

Value-level app context. Factories, guards, env, and final assembly all share one private owner identity (SPEC §6.2.1).

Signature

ts
interface KovoContract<
  RawRequest extends globalThis.Request = globalThis.Request,
  SessionValue = never,
  DbValue = never,
  EnvValue extends Record<string, unknown> = Record<never, never>,
  Request = RawRequest &
    ([SessionValue] extends [never] ? object : { session: SessionValue | null }) &
    ([DbValue] extends [never] ? object : { db: DbValue }) &
    ([EnvValue] extends [never] ? object : { env: Readonly<EnvValue> }),
  Owner extends string | undefined = string | undefined,
> {
  readonly [kovoContractBrand]: {
    readonly db: DbValue;
    readonly env: EnvValue;
    readonly owner: Owner;
    readonly rawRequest: RawRequest;
    readonly request: Request;
    readonly session: SessionValue;
  };
  /**
   * Adopt one exact advanced declaration from `@kovojs/server/agent` while inheriting this app's
   * request, session, DB, env, error, and trusted-client-IP providers.
   */
  readonly agent: <const Name extends string>(
    declaration: AgentDefinition<Name>,
  ) => {
    readonly [appAgentHandleBrand]: {
      readonly name: Name;
      readonly owner: Owner;
      readonly request: RawRequest;
    };
    readonly name: Name;
    session(
      request: RawRequest,
      options?: {
        onSessionSetCookie?: (rawSetCookie: string) => void;
      },
    ): Promise<AgentSession>;
  };
  readonly authenticated: Guard<Request, AuthenticatedAppRequest<Request>>;
  readonly endpoint: AppEndpointFactory<DbValue, Owner>;
  readonly env: Readonly<EnvValue>;
  readonly layout: AppLayoutFactory<AppReadRequest<Request>, Owner>;
  readonly mutation: AppMutationFactory<Request & TaskSchedulingRequest, Owner>;
  readonly publicAccess: typeof publicAccess;
  readonly query: AppQueryFactory<AppReadRequest<Request>, Owner>;
  readonly route: AppRouteFactory<AppReadRequest<Request>, Owner>;
  readonly task: AppTaskFactory<Owner>;
  readonly verifiedAccess: typeof verifiedAccess;
  integrateMutation<Definition extends { key: string }>(
    adapter: AppMutationAdapter<Definition>,
  ): Definition & {
    readonly [appDeclarationHandleBrand]: {
      readonly kind: 'mutation';
      readonly owner: Owner;
    };
  };
  all<const Items extends readonly Guard<Request, Request>[]>(
    ...items: Items
  ): Guard<Request, AppRequestForAccess<Request, Items>>;
  assemble<const Assembly extends AppAssemblyOptions<Request, DbValue, Owner>>(
    options: Assembly,
  ): KovoApp<{
    readonly contract: KovoContract<RawRequest, SessionValue, DbValue, EnvValue, Request, Owner>;
    readonly db: DbValue;
    readonly declarations: {
      readonly endpoint: Assembly extends {
        readonly endpoints?: readonly (infer Handle)[];
      }
        ? Handle
        : never;
      readonly layout: Assembly extends {
        readonly layouts?: readonly (infer Handle)[];
      }
        ? Handle
        : never;
      readonly mutation: Assembly extends {
        readonly mutations?: readonly (infer Handle)[];
      }
        ? Handle
        : never;
      readonly query: Assembly extends {
        readonly queries?: readonly (infer Handle)[];
      }
        ? Handle
        : never;
      readonly route: Assembly extends {
        readonly routes?: readonly (infer Handle)[];
      }
        ? Handle
        : never;
      readonly task: Assembly extends {
        readonly tasks?: readonly (infer Handle)[];
      }
        ? Handle
        : never;
    };
    readonly env: Readonly<EnvValue>;
    readonly rawRequest: RawRequest;
    readonly request: Request;
    readonly session: SessionValue;
  }>;
  owns<KeyedRequest extends Request = Request, Key = unknown>(
    keyOf: (request: KeyedRequest) => Key,
    keyColumn: AnyPgColumn<{ data: Key }>,
  ): Guard<Request, AuthenticatedAppRequest<Request>>;
  rateLimit(options: RateLimitOptions<Request>): Guard<Request>;
  role(role: string): Guard<Request, AuthenticatedAppRequest<Request>>;
}

LayoutHandle#

Named app-scoped layout handle.

Signature

ts
interface LayoutHandle<Owner extends string | undefined = string | undefined> {
  readonly [appDeclarationHandleBrand]: {
    readonly kind: 'layout';
    readonly owner: Owner;
  };
}

MutationHandle#

Named app-scoped mutation handle with inferred input/result/error payloads.

Signature

ts
interface MutationHandle<
  Input = unknown,
  Value = unknown,
  Errors extends Record<string, Schema<unknown>> = Record<string, Schema<unknown>>,
  Owner extends string | undefined = string | undefined,
> extends MutationFormDefinition<string, unknown> {
  readonly [appDeclarationHandleBrand]: {
    readonly kind: 'mutation';
    readonly owner: Owner;
  };
  readonly errors?: Errors;
  readonly input: Schema<Input>;
  readonly __kovoMutationTypes?: (input: Input, errors: Errors) => Value;
}

QueryHandle#

Named app-scoped query handle with inferred input/result and handle-bound optimism.

Signature

ts
interface QueryHandle<
  QueryInput = undefined,
  Value = JsonValue,
  Owner extends string | undefined = string | undefined,
> {
  readonly [appDeclarationHandleBrand]: {
    readonly kind: 'query';
    readonly owner: Owner;
  };
  readonly args: [QueryInput] extends [undefined]
    ? undefined
    : Schema<QueryInput> & {
        <Props extends object>(
          mapper: (props: Props) => QueryInput,
        ): {
          args: (props: Props) => QueryInput;
          query: { key: string };
          schema: Schema<QueryInput>;
        };
      };
  readonly key: string;
  optimistic(status: 'await-fragment'): {
    readonly [appOptimisticBindingBrand]: {
      readonly input: never;
      readonly owner: Owner;
      readonly value: Value;
    };
  };
  optimistic<InputSchema extends Schema<unknown>>(
    input: InputSchema,
    policy: [QueryInput] extends [undefined]
      ? (value: Readonly<Value>, input: NoInfer<InferSchema<InputSchema>>) => Value
      : {
          apply: (value: Readonly<Value>, input: NoInfer<InferSchema<InputSchema>>) => Value;
          keys: (input: NoInfer<InferSchema<InputSchema>>) => readonly QueryInput[];
        },
  ): {
    readonly [appOptimisticBindingBrand]: {
      readonly input: InferSchema<InputSchema>;
      readonly owner: Owner;
      readonly value: Value;
    };
  };
}

RouteHandle#

Named app-scoped route handle.

Signature

ts
interface RouteHandle<
  Path extends string = string,
  Owner extends string | undefined = string | undefined,
> {
  readonly [appDeclarationHandleBrand]: {
    readonly kind: 'route';
    readonly owner: Owner;
  };
  readonly path: Path;
}

AppTaskHandle#

Named app-scoped durable-task handle.

Signature

ts
interface TaskHandle<
  Input = unknown,
  Value = unknown,
  Owner extends string | undefined = string | undefined,
> {
  readonly [appDeclarationHandleBrand]: {
    readonly kind: 'task';
    readonly owner: Owner;
  };
  readonly input: Schema<Input>;
  readonly key: string;
  readonly run: (
    input: Input,
    context: import('./task.js').TaskRunContext,
  ) => Promise<Value> | Value;
  readonly __kovoTaskTypes?: (input: Input) => Value;
}

AccessDecision#

Optional structured access decision for SPEC §10 default-deny surfaces.

A guard-chain decision is the executable readonly guard array itself: the same guards run at request time and project their private names into access audits. publicAccess(reason) and verifiedAccess are the explicit no-guard sentinels.

Signature

ts
type AccessDecision =
  | readonly {
      (...args: never[]): GuardResult | Promise<GuardResult>;
    }[]
  | PublicAccess
  | VerifiedMachineAccess;

PublicAccess#

A human-justified public access decision.

Signature

ts
interface PublicAccess {
  kind: 'public';
  reason: string;
}

VerifiedMachineAccess#

A structured access decision backed by verified machine authentication.

Signature

ts
interface VerifiedMachineAccess {
  kind: 'verified-machine-auth';
}

Domain#

An invalidation domain: a named unit of cache currency that queries read and mutations touch.

Signature

ts
interface Domain<Key extends string = string> {
  key: Key;
}

SchemaValidationError#

Thrown by a schema's parse when input is invalid; carries the per-field issues.

Signature

ts
class SchemaValidationError extends Error {
  readonly issues: readonly ValidationIssue[];

  constructor(issues: readonly ValidationIssue[]) {
    super(firstValidationIssueMessage(issues));
    this.name = 'SchemaValidationError';
    this.issues = issues;
  }
}

FileLike#

Minimal uploaded-file shape accepted by s.file() schemas (SPEC.md §6).

Signature

ts
interface FileLike {
  arrayBuffer(): Promise<ArrayBuffer>;
  name: string;
  size: number;
  type: string;
}

FileSchema#

File-upload schema produced by s.file(); chains a size limit, a verified content-type allowlist via .accept(...), and .store() (SPEC.md §6; KV428 SPEC §6.6/§9.1).

KV428 (plans/secure-framework.md Phase 6 Tier 1): the legacy .mime() was REMOVED — it trusted the client-declared file.type, the verbatim-client-MIME hole. The replacement .accept(...) checks against the SERVER-SNIFFED type (accept([...])) or takes the audited accept.unverified([...], justification) escape, which is surfaced in kovo explain --capabilities.

Signature

ts
interface FileSchema extends Schema<FileLike> {
  maxBytes(value: number): FileSchema;
  /**
   * Restrict accepted uploads to an allowlist of content types. Pass `accept([...types])` from
   * `@kovojs/server` to check against the SERVER-SNIFFED bytes (server truth), or
   * `accept.unverified([...types], justification)` to trust the client-declared MIME (the audited
   * escape, surfaced in `kovo explain capabilities`). KV428 (SPEC §6.6/§9.1).
   */
  accept(acceptance: UnverifiedAcceptance | readonly string[]): FileSchema;
  /**
   * Parse an uploaded file and, for verified `accept([...])`, enforce the allowlist against the
   * server-sniffed bytes rather than the client-declared MIME (SPEC §6.6/§9.1, KV428).
   */
  parseAsync(input: unknown): Promise<FileLike>;
  store(options: StoredFileSchemaOptions): StoredFileSchema;
}

FileSchemaOptions#

Size/content-type constraints captured by an s.file() schema (SPEC.md §6; KV428 §6.6/§9.1).

Signature

ts
interface FileSchemaOptions {
  maxBytes?: number;
  /**
   * The accepted content types: a plain string allowlist checked against the SERVER-SNIFFED type,
   * or an `accept.unverified(...)` acceptance that trusts the client-declared MIME (audited).
   */
  accept?: UnverifiedAcceptance | readonly string[];
}

InferSchema#

Extract the parsed value type of a Schema.

Signature

ts
type InferSchema<T> = T extends Schema<infer Value> ? Value : never;

NumberSchema#

Numeric schema produced by s.number(); chains int/min/default refinements (SPEC.md §6).

Signature

ts
interface NumberSchema extends Schema<number> {
  default(value: number): NumberSchema;
  int(): NumberSchema;
  max(value: number): NumberSchema;
  min(value: number): NumberSchema;
  optional(): Schema<number | undefined>;
}

Schema#

A validator that parses unknown input into a typed value (throwing SchemaValidationError on failure).

Signature

ts
interface Schema<T> {
  parse(input: unknown): T;
}

StoredFileSchema#

Stored-upload schema produced by s.file().store(...) (SPEC.md §6).

Signature

ts
interface StoredFileSchema extends Schema<StoredFileUpload> {
  parseAsync(input: unknown): Promise<StoredFileUpload>;
}

StoredFileSchemaOptions#

Options for s.file().store(...): storage capability, an optional key namespace, and metadata (SPEC.md §6; KV428 SPEC §6.6/§9.1).

KV428: the storage key is SERVER-GENERATED and opaque by construction (a random UUID, optionally namespaced by keyPrefix). The client filename is NEVER the key — it is sanitized download metadata only, killing path-traversal/overwrite. The legacy author-controlled key callback was removed; pass keyPrefix to namespace uploads.

Signature

ts
interface StoredFileSchemaOptions {
  /** Optional namespace segment for the server-minted random key (e.g. `'avatars'`). */
  keyPrefix?: string;
  metadata?: (file: FileLike) => Readonly<Record<string, string>>;
  storage: StoragePutCapability;
}

StoredFileUpload#

Result of a stored upload produced by s.file().store(...) (SPEC.md §6).

Signature

ts
interface StoredFileUpload {
  file: FileLike;
  key: ScopedKey;
  /**
   * Framework-pinned storage metadata. Mutable `Date` internal slots cannot cross the validated
   * args receipt, so `lastModified` is normalized to an ISO timestamp string (SPEC §10.3 C15).
   */
  storage: Readonly<Omit<StorageObjectInfo, 'lastModified'> & { readonly lastModified?: string }>;
}

StringSchema#

String schema produced by s.string(); chains a blessed-format check (.email()/.url()/ .uuid()/.slug()), a linear-engine .pattern(...) literal, or the audited .matches(unsafeRegex) escape (KV434, SPEC §6.6/§9.5).

KV434: blessed formats are backtracking-free BY-CONSTRUCTION; .pattern(literal) compiles to Kovo's bounded Thompson-NFA/Pike VM subset; unsupported syntax must use unsafeRegex(re, justification), the audited escape surfaced in kovo explain capabilities.

Signature

ts
interface StringSchema extends Schema<string> {
  default(value: string): StringSchema;
  optional(): Schema<string | undefined>;
  /**
   * Admit line terminators in string values while still rejecting other raw C0 controls and DEL
   * (SPEC §6.6).
   */
  multiline(): StringSchema;
  /** Admit arbitrary raw control characters, including line terminators (SPEC §6.6). */
  allowControlChars(): StringSchema;
  /** Restrict to one of the blessed backtracking-free formats (KV434). */
  format(name: BlessedFormatName): StringSchema;
  email(): StringSchema;
  url(): StringSchema;
  uuid(): StringSchema;
  slug(): StringSchema;
  /**
   * Require the value to match a COMPILE-VISIBLE literal pattern. Supported syntax is matched by
   * Kovo's linear engine; unsupported syntax must use `.matches(unsafeRegex(...))`.
   */
  pattern(source: RegExp | string): StringSchema;
  /** Match against an audited {@link unsafeRegex} brand — the escape for an unanalyzable pattern (KV434). */
  matches(brand: UnsafeRegexBrand): StringSchema;
}

ValidationFailurePayload#

The wire shape of a schema validation failure: the collected per-field issues. Returned on the mutation 422 response so forms can render field errors (SPEC §9.2).

Signature

ts
interface ValidationFailurePayload {
  issues: readonly ValidationIssue[];
}

ValidationIssue#

A single field-level validation failure: a human message and the path of record keys/array indices locating it. Carried on SchemaValidationError.issues and surfaced on the mutation 422 typed-error path (SPEC §9.2).

Signature

ts
interface ValidationIssue {
  message: string;
  path: readonly string[];
}

MutationDefinition#

The full definition object passed to {@link mutation} (SPEC §6.3/§9.1/§10.3): the key, input schema, optional errors, guard, csrf posture, optimistic map, redirectTo/defaultRedirectTo POST-redirect-GET targets, stream/transaction hooks, and the handler body. Typed mutation()'s parameter and return shape.

Signature

ts
interface MutationDefinition<
  Key extends string = string,
  InputSchema extends Schema<unknown> = Schema<unknown>,
  Errors extends Record<string, Schema<unknown>> = Record<string, Schema<unknown>>,
  Request = unknown,
  Value = unknown,
  GuardedRequest extends Request = Request,
> {
  access?: AccessDecision;
  csrf?: CsrfOptions<Request> | false;
  /**
   * Required audit text when `csrf` is exactly `false` (SPEC §6.6/§9.1).
   * Protected mutations cannot carry this field, so explain output always reflects
   * the declaration's exact security posture rather than a generic placeholder.
   */
  csrfJustification?: string;
  /** Static/common POST-redirect-GET target for successful no-JS submissions (SPEC §9.1). */
  defaultRedirectTo?: string;
  /** internal Derived from `input` when the schema contains `s.file()` fields. */
  enctype?: 'multipart/form-data';
  errors?: Errors;
  /** internal Top-level input field names that require multipart form encoding. */
  fileFields?: readonly string[];
  guard?: Guard<Request, GuardedRequest>;
  handler: (
    input: InferSchema<InputSchema>,
    request: GuardedRequest,
    context: {
      fail<const Code extends Extract<keyof Errors, string>>(
        code: Code,
        payload: InferSchema<Errors[Code]> & JsonValue,
      ): MutationFail<Code, InferSchema<Errors[Code]> & JsonValue>;
      invalidate<const DomainKey extends string, InvalidationInput = unknown>(
        domain: Domain<DomainKey>,
        options?: InvalidateOptions<InvalidationInput>,
      ): ChangeRecord<DomainKey, InvalidationInput>;
      setCookie?: (name: string, value: string, options?: CookieOptions) => void;
    },
  ) => Promise<Value | MutationFail> | Value | MutationFail;
  input: InputSchema;
  key: Key;
  /**
   * Stable machine-caller identity used only to scope `Kovo-Idem` replay for a `csrf: false`
   * mutation (SPEC §6.6/§10.3). Kovo invokes this selector exactly once, after the access/guard
   * decision succeeds, validates an exact 1..1,024-code-unit string, and commits the exact UTF-16LE
   * encoding of its length-framed value through SHA-256 before replay-store access. Return a stable
   * public caller/tenant id rather than a credential. Protected-CSRF mutations cannot declare this
   * field.
   *
   * A replay-enabled `csrf: false` request without this binding fails closed before handler work.
   * TypeScript's discriminant is an authoring guardrail; runtime validation and the replay sink own
   * enforcement.
   */
  machineReplayPrincipal?: (request: GuardedRequest) => string;
  optimistic?: Record<
    string,
    | ((draft: any, input: InferSchema<InputSchema>) => void)
    | {
        keys: (
          input: InferSchema<InputSchema>,
        ) => string | Record<string, string | number | boolean>;
        transform: (draft: any, input: InferSchema<InputSchema>) => void;
      }
    | 'await-fragment'
  >;
  /** Explicit privilege-lifecycle door; Kovo never infers this semantic fact from table names. */
  principalEpoch?:
    | {
        readonly action: 'advance';
        readonly principal: (input: InferSchema<InputSchema>, request: GuardedRequest) => string;
        readonly reason:
          | 'principal-created'
          | 'password-change'
          | 'role-change'
          | 'tenant-change'
          | 'admin-change'
          | 'provider-revocation'
          | 'manual-security-invalidation';
      }
    | {
        readonly action: 'tombstone';
        readonly principal: (input: InferSchema<InputSchema>, request: GuardedRequest) => string;
        readonly reason: 'principal-deletion' | 'provider-deletion';
      };
  queue?: string | true | ReturnType<typeof queue>;
  /**
   * Mutation-local success redirect policy for dynamic POST-redirect-GET targets (SPEC §9.1 PRG).
   * Accepts three forms:
   * - a plain `string` path (legacy/back-compat, not route-table validated);
   * - a typed {@link Redirect} value from `redirect('/chat/:id', { params })` (`@kovojs/core`,
   *   SPEC §6.4:724) — the preferred create-then-navigate form. Because the typed value can only be
   *   minted by a path-typed `redirect()` call, the target participates in KV220 route-table path
   *   typing and route-rename propagation: a wrong path or param is a type error at the `redirect()`
   *   call, and renaming the route turns every such `redirect()` red (SPEC §6.2/§6.4:724);
   * - a function of the success `result` returning either form, for the common create-then-navigate
   *   case where the new row id is only known after the handler runs, e.g.
   *   `redirectTo: (r) => redirect('/chat/:id', { params: { id: r.value.id } })`.
   * The resolved `location` is re-sanitized at the framework Location sink (SPEC §6.6).
   */
  redirectTo?:
    | string
    | Redirect
    | ((result: MutationSuccess<Value, InferSchema<InputSchema>>) => string | Redirect);
  registry?: {
    inferredTouches?: readonly {
      crossTable?: true;
      domain: string;
      keys: null | string;
      via?: string;
    }[];
    queries?: readonly import('../query.js').QueryDefinition<string, any, any, any>[];
    /** Raw-SQL write table allowlist for opaque mutation writes (SPEC §10.3). */
    tables?: readonly string[];
    touches?: readonly Domain[];
  };
  stream?: (context: {
    input: InferSchema<InputSchema>;
    request: GuardedRequest;
    result: MutationSuccess<Value, InferSchema<InputSchema>>;
  }) =>
    | AsyncIterable<
        | { kind: 'done'; reason?: string }
        | {
            html: ServerFragmentRenderable;
            kind: 'fragment';
            mode?: 'append' | 'replace';
            target: string;
          }
        | {
            delta?: boolean;
            key?: string;
            kind: 'query';
            name: string;
            value: unknown;
            version?: number | string;
          }
        | {
            kind: 'text';
            mode?: 'append' | 'checkpoint';
            target: string;
            text: string;
          }
      >
    | Iterable<
        | { kind: 'done'; reason?: string }
        | {
            html: ServerFragmentRenderable;
            kind: 'fragment';
            mode?: 'append' | 'replace';
            target: string;
          }
        | {
            delta?: boolean;
            key?: string;
            kind: 'query';
            name: string;
            value: unknown;
            version?: number | string;
          }
        | {
            kind: 'text';
            mode?: 'append' | 'checkpoint';
            target: string;
            text: string;
          }
      >;
  transaction?: <Result>(
    request: Request,
    run: (transactionRequest: GuardedRequest) => Promise<Result>,
  ) => Promise<Result>;
}

MutationFail#

A typed mutation failure outcome (SPEC §9.2): a declared error code plus its validated payload, served as HTTP 422 (validation/app fail()), 429 (rate limit, with optional retryAfter), framework-owned authenticated authorization denial as HTTP 403, or a KV429 stale-version optimistic-concurrency conflict as HTTP 409 (SPEC §10.3/§11.1). Produced via MutationContext.fail for app failures, by guards for authorization failures, and by the lifecycle when a StaleVersionError is thrown.

Signature

ts
interface MutationFail<Code extends string = string, Payload = unknown> {
  error: {
    code: Code;
    payload: Payload;
  };
  ok: false;
  retryAfter?: number;
  status: 403 | 409 | 422 | 429;
}

MutationFormAttributes#

Attributes emitted for a SPEC §6.3 enhanced mutation form.

Signature

ts
interface MutationFormAttributes<Key extends string = string, Request = unknown> {
  /** No-JS mutation endpoint path derived from the typed mutation key. */
  action: `/_m/${Key}`;
  /** Stable mutation key metadata used by enhanced submit/runtime tooling. */
  'data-mutation': Key;
  /** Enables the SPEC §9.1 enhanced fragment submit path. */
  enhance: true;
  /** Required for no-JS file uploads when the mutation input contains `s.file()`. */
  enctype?: 'multipart/form-data';
  /** Mutation forms post by default. */
  method: 'post';
  /** Typed mutation value retained for server JSX runtime CSRF injection. */
  mutation: MutationFormDefinition<Key, Request>;
}

MutationFormDefinition#

The minimal mutation reference ({@link MutationDefinition} key plus csrf posture) carried on a {@link MutationFormAttributes} mutation field so the server JSX runtime can inject the CSRF token into an enhanced form (SPEC §6.3/§9.1).

Signature

ts
interface MutationFormDefinition<Key extends string = string, Request = never> {
  readonly [mutationFormDefinitionBrand]: 'kovo-mutation-form-definition';
  csrf?: CsrfOptions<Request> | false;
  enctype?: 'multipart/form-data';
  fileFields?: readonly string[];
  key: Key;
}

MutationHandlerRequest#

Mutation handler request shape with the provider DB narrowed to the transaction handle.

Signature

ts
type MutationHandlerRequest<Request> = Request extends { db: infer DbValue }
  ? Omit<Request, 'db'> & {
      db: DbValue extends object ? Omit<DbValue, 'transaction'> : DbValue;
    }
  : Request;

MutationResult#

The outcome of a mutation: {@link MutationSuccess} or {@link MutationFail} (SPEC §9.1/§9.2).

Signature

ts
type MutationResult<Value, Input = unknown> = MutationFail | MutationSuccess<Value, Input>;

MutationSuccess#

A successful mutation outcome (SPEC §9.1/§10.3): the returned value, the validated input, the emitted changes, the query names/instances to rerun, and any responseHeaders to apply (e.g. Set-Cookie).

Signature

ts
interface MutationSuccess<Value, Input = unknown> {
  changes: ChangeRecord[];
  input: Input;
  rerunQueryInstances?: {
    input?: unknown;
    instanceKey?: string;
    key: string;
    whole?: boolean;
  }[];
  rerunQueries: string[];
  ok: true;
  responseHeaders?: import('../response.js').ResponseHeaders;
  value: Value;
}

QueryDefinition#

The shape of a query: its key, load, reads domains, and optional args/output/guard/version.

Signature

ts
interface QueryDefinition<
  Key extends string = string,
  Value = JsonValue,
  Input = unknown,
  Request = unknown,
> {
  access?: AccessDecision;
  args?: Schema<Input>;
  /**
   * Delta-eligible collections for this query. When present, the server can
   * emit a change-record-scoped delta (SPEC §9.1.1) instead of the full value
   * when the delta is smaller. The compiler populates this; framework/test code
   * may set it directly.
   */
  delta?: readonly { domain: string; key: string; path: string }[];
  guard?: {
    call(request: Request): GuardResult | Promise<GuardResult>;
  }['call'];
  instanceKey?: QueryInstanceKey<Input>;
  load?(
    input: Input,
    context: {
      request: Request;
      signal: AbortSignal;
    } & (Request extends { db: infer RequestDb } ? { db: RequestDb } : { db?: never }) &
      (Request extends { session: infer Session } ? { session: Session } : { session?: never }) &
      (Request extends { env: infer RequestEnv } ? { env: Readonly<RequestEnv> } : { env?: never }),
  ): Promise<Value> | Value;
  key: Key;
  output?: Schema<Value>;
  read?: QueryReadConfig;
  reads?: readonly Domain[];
  version?: ((input: Input, value: Value) => number | string | undefined) | number | string;
}

QueryInstanceKey#

Compute or declare a stable per-input query instance key (SPEC §9.4/§10.2).

Signature

ts
type QueryInstanceKey<Input> = ((input: Input) => string | undefined) | string;

QueryResult#

Extract the resolved value type a query's load produces.

Signature

ts
type QueryResult<Query> = Query extends { load: (...args: never[]) => infer Value }
  ? Awaited<Value>
  : unknown;

StaleVersionError#

KV429 RUNTIME — Stale-version conflict signal for optimistic-concurrency mutations.

SPEC §10.3/§11.1 (KV429): a mutation handler whose table declares kovo((columns) => ({ atomic: columns.stock, version: columns.lockVersion })) MUST fold check+act into one UPDATE…WHERE. When 0 rows are updated (i.e. the version predicate did not match — the row was concurrently modified since the version was read), the handler throws a StaleVersionError. The runMutation lifecycle catches this error and returns a typed HTTP 409 (STALE_VERSION) outcome distinct from the IDEMPOTENCY_CONFLICT 409 produced by the replay-idempotency path.

On a 409 stale-version response the enhanced client refetches the fresh version and retries the mutation with the updated version token.

Copyable example

ts
import { compareAndSet } from '@kovojs/drizzle';
import { StaleVersionError } from '@kovojs/server';

// In a mutation handler:
const cas = await compareAndSet(
  db.update(products)
    .set({ stock: sql`${products.stock} - ${qty}`, ver: sql`${products.ver} + 1` })
    .where(and(eq(products.id, id), eq(products.ver, input.prevVer))),
);
if (!cas.ok) throw new StaleVersionError();

Signature

ts
class StaleVersionError extends Error {
  /** Always `'StaleVersionError'` for instanceof-free duck-typing (cross-realm / bundled). */
  readonly kind = 'StaleVersionError' as const;

  constructor(message = 'Stale version: concurrent modification detected (KV429)') {
    super(message);
    this.name = 'StaleVersionError';
  }
}

StaleVersionConflict#

The typed 409 stale-version mutation failure returned by runMutation when the handler throws a StaleVersionError (KV429, SPEC §10.3/§11.1). Distinct from the IDEMPOTENCY_CONFLICT 409 returned by the replay-idempotency path.

The client refetches the fresh version and retries the mutation.

Signature

ts
interface StaleVersionConflict {
  error: {
    code: 'STALE_VERSION';
    payload: Record<string, never>;
  };
  ok: false;
  status: 409;
}

EndpointDefinition#

The body passed to endpoint(): handler, method/mount, and the unsafe-method CSRF choice.

Signature

ts
type EndpointDefinition<
  Method extends EndpointMethod = EndpointMethod,
  Mount extends EndpointMount = 'exact',
  Db = unknown,
> =
  | ({
      access?: AccessDecision;
      auth?: EndpointAuthDeclaration;
      db?: false;
      handler: EndpointHandler;
      method: Method;
      reason: string;
      response: EndpointResponsePosture;
    } & EndpointMountDefinition<Mount> &
      ({ csrf?: true; csrfJustification?: never } | { csrf: false; csrfJustification: string }))
  | (EndpointDbDefinitionBase<Method, Db> & { reason: string } & EndpointMountDefinition<Mount> &
      ({ csrf?: true; csrfJustification?: never } | { csrf: false; csrfJustification: string }));

EndpointMethod#

Canonical uppercase HTTP method for an endpoint; custom verbs are allowed.

Signature

ts
type EndpointMethod =
  | 'DELETE'
  | 'GET'
  | 'HEAD'
  | 'OPTIONS'
  | 'PATCH'
  | 'POST'
  | 'PUT'
  | (string & {});

EndpointRequest#

A Request guaranteed to carry no session, as endpoint handlers receive.

Signature

ts
type EndpointRequest = Request & { readonly session?: never };

EndpointResponsePosture#

Audit metadata for the raw Response an endpoint returns. appOwnedSafety means application code owns body encoding and response-header safety for this raw HTTP escape hatch (SPEC §9.1).

Signature

ts
interface EndpointResponsePosture {
  appOwnedSafety: boolean;
  body: EndpointResponseBodyPosture;
  cache: EndpointCachePosture;
  /** Compiler-reviewed inputs and version-key obligations when `cache` is `public`. */
  cacheInfluence?: SharedCacheInfluenceDeclaration;
  /** Bounded, explain-visible deadline extension for a legitimate stream or long poll. */
  longLived?: EndpointLongLivedResponsePosture;
  /**
   * Exact cross-origin redirect origins this raw endpoint may emit in a `Location` header.
   * Same-origin paths need no entry; external origins require an audit-readable reason.
   */
  redirectAllowlist?: readonly RedirectLocationAllowlistEntry[];
  /**
   * Reserved response headers this raw endpoint intentionally writes. Framework protocol,
   * credential, redirect, and security-policy headers are rejected by the runtime posture verifier
   * unless named here, because raw endpoints bypass the framework response header sinks.
   */
  reservedHeaders?: readonly string[];
}

Guard#

An access guard over a request; may refine the request type when it passes.

Signature

ts
interface Guard<Request, RefinedRequest extends Request = Request> {
  (request: Request): GuardResult | Promise<GuardResult>;
  readonly refines?: (request: Request) => request is RefinedRequest;
}

SessionProvider#

A function that resolves the session value from a raw request (or null).

Signature

ts
type SessionProvider<RawRequest, SessionValue> = (
  request: RawRequest,
) =>
  | Promise<SessionProviderResult<SessionValue> | SessionValue | null | undefined>
  | SessionProviderResult<SessionValue>
  | SessionValue
  | null
  | undefined;

LayoutDefinition#

The body passed to layout(): optional parent, guard, queries, and chrome render function.

Signature

ts
interface LayoutDefinition<
  Request = unknown,
  Queries extends Readonly<Record<string, QueryDefinition<string, any, any, Request>>> = Readonly<
    Record<string, QueryDefinition<string, any, any, Request>>
  >,
  Page extends LayoutRenderResult = LayoutRenderResult,
  Regions extends LayoutRegionResults = LayoutRegionResults,
> extends PageHintOptions {
  access?: AccessDecision;
  boundaries?: RouteBoundaries<Request, Page>;
  guard?: Guard<Request>;
  parent?: LayoutDeclaration<Request, any, LayoutRenderResult, any>;
  queries?: Queries;
  render?: (
    queries: LayoutQueryResults<Queries>,
    state: undefined,
    slots: {
      /** The child layout or route page output this layout wraps. */
      children: ComponentChild;
      /** Named route-level sibling regions rendered before layout composition. */
      regions: Regions;
      /** The request after configured app lifecycle providers have run. */
      request: Request;
    },
  ) => Page | Promise<Page>;
}

RouteDefinition#

The body of a route passed to route(): page, param/search schemas, guards, and meta/hints.

Signature

ts
interface RouteDefinition<
  Path extends string,
  ParamsSchema extends Schema<Record<string, string>> | undefined = undefined,
  SearchSchema extends Schema<Record<string, RouteSearchValue>> | undefined = undefined,
  Request = unknown,
  Page extends RoutePageResult = RoutePageResult,
  GuardedRequest extends Request = Request,
  Regions extends RouteRegionDefinitions<any, GuardedRequest, Page> = RouteRegionDefinitions<
    any,
    GuardedRequest,
    Page
  >,
> extends Omit<PageHintOptions, 'meta'> {
  access?: AccessDecision;
  boundaries?: RouteBoundaries<Request, Page>;
  guard?: Guard<Request, GuardedRequest>;
  layout?: LayoutDeclaration<any, any, any, RouteRegionResults<Regions>>;
  meta?:
    | RouteMetaSource<RouteRequest<Path, ParamsSchema, SearchSchema>>
    | readonly RouteMetaSource<RouteRequest<Path, ParamsSchema, SearchSchema>>[];
  onUnauthenticated?: UnauthenticatedHandler<Request>;
  page?: (
    context: RouteRequest<Path, ParamsSchema, SearchSchema>,
    request: GuardedRequest,
  ) =>
    | Page
    | NotFound
    | Redirect
    | RouteResponseOutcome
    | Promise<Page | NotFound | Redirect | RouteResponseOutcome>;
  params?: ParamsSchema;
  regions?: Regions &
    RouteRegionDefinitions<RouteRequest<Path, ParamsSchema, SearchSchema>, GuardedRequest, Page>;
  search?: SearchSchema;
  staticPaths?: readonly string[];
}

RoutePageResult#

Non-string page body value accepted from public route page callbacks (SPEC §4.1, §9.1).

Signature

ts
type RoutePageResult =
  | boolean
  | null
  | number
  | readonly RoutePageResult[]
  | undefined
  | object;

RouteRequest#

The typed context a route page receives: parsed params, search, the path, and signUrl.

Signature

ts
interface RouteRequest<
  Path extends string,
  ParamsSchema extends Schema<Record<string, string>> | undefined = undefined,
  SearchSchema extends Schema<Record<string, RouteSearchValue>> | undefined = undefined,
> {
  params: ParamsSchema extends Schema<infer Params> ? Params : CorePathParams<Path>;
  path: Path;
  search: SearchSchema extends Schema<infer Search> ? Search : Record<string, JsonValue>;
  /**
   * Mint a signed, short-lived, scope-bound capability URL for a stored object (SPEC §6.6 / §9.1).
   * The URL points at the framework-owned download route, whose verify sink runs before any storage
   * read so an object is un-dereferenceable without a token minted for that exact object. Present
   * only when the app mounts exactly one `createStorageDownloadEndpoint({ secret })`; `undefined`
   * otherwise, so a page must handle its absence. The minted URL is a BEARER credential (leakage
   * mitigated by short expiry / narrow scope / optional one-time, NOT proven).
   */
  signUrl?: SignUrlContext['signUrl'];
}

ResponseHeaders#

A header bag mapping header names to values.

Signature

ts
type ResponseHeaders = Record<string, ResponseHeaderValue>;

ResponseHeaderValue#

A single header value: one string or a list of strings.

Signature

ts
type ResponseHeaderValue = string | string[];

AppResponseHeaders#

Direct app-owned metadata accepted on structured response outcomes.

Use contentType, etag, filename/disposition, redirect(), and the typed mutation cookie builder for the corresponding dedicated response fields (SPEC §9.1.1; KV415).

Signature

ts
type AppResponseHeaders = Partial<Record<AppResponseHeaderName, ResponseHeaderValue>>;

RouteResponseBody#

A renderable route body: a string, bytes, an ArrayBuffer, or a byte stream.

Signature

ts
type RouteResponseBody = ArrayBuffer | ReadableStream<Uint8Array> | Uint8Array | string;

RouteResponseOutcome#

An opaque non-document route outcome (file/stream) produced only by {@link respond}.

SPEC §2 / §6.6 / §9.1: the private type brand is author-time ergonomics only. Runtime route and document dispatch re-check a module-private witness and consume an inaccessible pinned snapshot, so a structural object, cast, or post-construction mutation cannot acquire response authority.

Signature

ts
interface RouteResponseOutcome {
  readonly body: RouteResponseBody;
  readonly contentDisposition: string;
  readonly contentType: string;
  readonly etag?: string;
  readonly headers?: Readonly<Record<string, string>>;
  readonly routeResponse: true;
  readonly [routeResponseOutcomeBrand]: true;
}

UnsafeInlineAcceptance#

Opaque audited receipt for rendering bytes inline without Kovo deep-sniffing them (SPEC §6.6/§9.1). Construct only with {@link unsafeInline}; structural lookalikes fail closed.

Signature

ts
interface UnsafeInlineAcceptance {
  readonly [unsafeInlineAcceptanceBrand]: { readonly kind: 'unsafe-inline-response' };
  readonly justification: string;
}

DocumentConfig#

Structured document facts consumed by framework-owned document assembly (SPEC.md §9.5).

Signature

ts
interface DocumentConfig {
  readonly [documentConfigSentinel]: true;
  readonly bodyAttrs: DocumentShellAttributes;
  readonly bodyEnd: readonly string[];
  readonly bodyStart: readonly string[];
  readonly csp: CspInlineMetadata;
  readonly head: readonly string[];
  readonly htmlAttrs: DocumentShellAttributes;
  readonly lang?: string;
}

DocumentDeclaration#

Structured document declaration accepted by createApp({ document }) (SPEC.md §9.5).

Signature

ts
type DocumentDeclaration =
  | DocumentConfig
  | ((context: DocumentAuthoringContext) => DocumentConfig);

DeferProps#

Props for {@link Defer}, the public JSX-native route-region deferral primitive.

Signature

ts
interface DeferProps {
  /** Stable fragment target that the deferred stream will morph into. */
  target: string;
  /** Region priority. `critical` renders immediately; deferred regions stream after the shell. */
  priority?: RegionPriority;
  /** Placeholder content rendered with normal JSX/text escaping rules. */
  fallback?: ServerRenderable;
  /** Render the real region content from server truth. */
  render: () => ServerRenderable;
  /** Stylesheets required by the deferred region when it is inserted. */
  stylesheets?: readonly (string | StylesheetAsset)[];
  /** Per-region render deadline before the fallback is marked failed. */
  timeoutMs?: number;
}

ServerRenderable#

Renderable values accepted by server JSX primitives.

Strings and numbers render as escaped text, JSX/runtime HTML renders as markup, arrays flatten, and promises are awaited by the server renderer (SPEC §8).

Signature

ts
type ServerRenderable =
  | ComponentChild
  | ServerRenderable[]
  | readonly ServerRenderable[]
  | TrustedHtml
  | Promise<ServerRenderable>;

RouteMeta#

Resolved document <head> metadata (title, description, OG image) for a route.

Signature

ts
interface RouteMeta {
  description?: string;
  image?: string;
  title?: string;
}

StylesheetAsset#

A resolved stylesheet asset for route/page hints (SPEC §13.1): the linked href, optional inlined criticalCss with its cspHash, and whether to preload it via Early Hints. Produced by {@link stylesheet} and accepted in {@link PageHintOptions}.

Signature

ts
interface StylesheetAsset {
  criticalCss?: string;
  cspHash?: string;
  /**
   * `true` defers the linked stylesheet behind a preload plus no-JS fallback. By default the
   * stylesheet remains render-blocking even when critical CSS is inlined.
   */
  deferFull?: boolean;
  href: string;
  preload?: boolean;
}

StylesheetDeclarationOptions#

Options for declaring an authored stylesheet asset (SPEC.md §13.1).

Signature

ts
interface StylesheetDeclarationOptions {
  /** Critical CSS to inline before the linked stylesheet identity. */
  criticalCss?: string | readonly string[];
  /**
   * How theme CSS prepended to critical CSS should be inlined. The default
   * (`'used'`) keeps only custom properties reachable from `criticalCss`
   * `var(...)` references; `'all'` keeps the full theme block.
   */
  criticalCssTheme?: 'all' | 'used';
  /** Optional CSP hash for the inlined critical CSS. */
  cspHash?: string;
  /**
   * `true` defers the linked stylesheet behind a preload plus no-JS fallback. By default the
   * stylesheet remains render-blocking even when critical CSS is inlined.
   */
  deferFull?: boolean;
  /** Public stylesheet href; local sources derive `/assets/<file>` when omitted. */
  href?: string;
  /** Whether Early Hints should preload the linked stylesheet. */
  preload?: boolean;
  /** Theme CSS to prepend to `criticalCss`. */
  theme?: StylesheetTheme;
}

StylesheetTheme#

Theme CSS accepted by {@link stylesheet}; usually a Kovo theme object from @kovojs/style.

Signature

ts
type StylesheetTheme = string | { readonly css: string };

CreateAppBootError#

Thrown by createApp when a required framework secret fails validation in production or an app-declared env schema fails validation in any mode. Carries every collected issues so boot fails fast with all problems at once rather than one-at-a-time. Distinct typed error so deploy tooling and tests can catch it precisely (SPEC §6.6).

Signature

ts
class CreateAppBootError extends Error {
  readonly name = 'CreateAppBootError';
  readonly issues: readonly EnvValidationIssue[];

  constructor(issues: readonly EnvValidationIssue[]) {
    super(formatBootError(issues));
    this.issues = issues;
  }
}

AppResponseHeaderName#

Header names an app may write directly on a structured response outcome.

Body representation, validators, disposition, redirects, cookies, and Kovo protocol fields use their dedicated typed APIs instead (SPEC §9.1.1; KV415).

Signature

ts
type AppResponseHeaderName = 'Cache-Control' | 'Last-Modified' | 'Vary';

@kovojs/server/agent#

Task: Agent sessions, typed tools, model decisions, and turn execution.

Source: packages/server/src/public-agent.ts

Values#

agent#

Declare an inline model adapter and exact tool set; compiler lowering witnesses its model IR.

Signature

ts
function agent<const Name extends string>(
  name: Name,
  options: AgentOptions,
): AgentDefinition<Name>;

agentContent#

Mark ordinary data with its admitted integrity. No content classifier is consulted.

Signature

ts
function agentContent<Value>(value: Value, integrity: AgentIntegrity): AgentContent<Value>;

createAgentSession#

Pin the invoking request/session. Ambient structural principals are rejected fail closed.

Signature

ts
async function createAgentSession<
  Request extends object,
  SessionValue = unknown,
  DbValue = unknown,
>(
  definition: AgentDefinition,
  options: CreateAgentSessionOptions<Request, SessionValue, DbValue>,
): Promise<AgentSession>;

runAgentTurn#

Run one model decision and, at most, one witnessed mutation effect.

Signature

ts
async function runAgentTurn(
  session: AgentSession,
  content: AgentContent | readonly AgentContent[],
): Promise<AgentTurnResult>;

tool#

Declare an exact mutation-backed tool; compiler lowering installs its finite operation witness.

Signature

ts
function tool<const Name extends string>(
  name: Name,
  options: AgentToolOptions,
): AgentToolDefinition<Name>;

Supporting types#

AgentContent#

Content admitted to an agent turn with an explicit, finite integrity level (SPEC §6.6).

Signature

ts
interface AgentContent<Value = unknown> {
  readonly [agentContentBrand]: 'kovo-agent-content';
  readonly integrity: AgentIntegrity;
  readonly value: Value;
}

AgentDefinition#

Public opaque declaration for one capability-bounded agent.

Signature

ts
interface AgentDefinition<Name extends string = string> {
  readonly [agentDefinitionBrand]: { readonly name: Name };
  readonly name: Name;
}

AgentIntegrity#

Closed integrity order carried by an agent session, from least to most trusted.

Signature

ts
type AgentIntegrity = 'principal' | 'retrieved' | 'untrusted' | 'validated';

AgentModelContext#

Finite model adapter context. fetch is the framework egress door, never ambient fetch.

Signature

ts
interface AgentModelContext {
  readonly fetch: typeof globalThis.fetch;
  readonly integrity: AgentIntegrity;
  readonly tools: readonly AgentToolDescriptor[];
}

AgentModelDecision#

The only model decisions accepted by the mediation door.

Signature

ts
type AgentModelDecision<Output = unknown> =
  | { readonly input: unknown; readonly kind: 'tool-call'; readonly tool: string }
  | { readonly kind: 'output'; readonly value: Output };

AgentOptions#

Inline finite model and the exact tools it may select.

Signature

ts
interface AgentOptions<Output = unknown> {
  readonly model: (
    turn: AgentContent,
    context: AgentModelContext,
  ) => AgentModelDecision<Output> | Promise<AgentModelDecision<Output>>;
  readonly tools: readonly AgentToolDefinition[];
}

AgentSession#

Public opaque mutable session; only runAgentTurn may attenuate its integrity.

Signature

ts
interface AgentSession {
  readonly [agentSessionBrand]: 'kovo-agent-session';
  readonly agent: string;
}

AgentToolDefinition#

Public opaque declaration for one mutation-backed tool.

Signature

ts
interface AgentToolDefinition<Name extends string = string> {
  readonly [agentToolBrand]: {
    readonly name: Name;
  };
  readonly name: Name;
}

AgentToolDescriptor#

A model-visible descriptor; it contains no executable mutation capability.

Signature

ts
interface AgentToolDescriptor {
  readonly description: string;
  readonly name: string;
}

AgentToolFailure#

Public projection of a failed mutation-backed tool execution.

Signature

ts
interface AgentToolFailure {
  readonly error: { readonly code: string; readonly payload?: unknown };
  readonly ok: false;
  readonly retryAfter?: number;
  readonly status: number;
}

AgentToolMutation#

Minimal typed mutation reference accepted by tool(); runtime requires the exact declaration.

Signature

ts
interface AgentToolMutation {
  readonly key: string;
}

AgentToolOptions#

Tool declaration: a model can select this name, but only the exact mutation can execute.

Signature

ts
interface AgentToolOptions {
  readonly description: string;
  readonly mutation: AgentToolMutation;
  /** Tool output can only introduce untrusted or retrieved content; it can never raise authority. */
  readonly resultIntegrity?: Extract<AgentIntegrity, 'retrieved' | 'untrusted'>;
}

AgentToolOutcome#

Public result projection; internal mutation bookkeeping is intentionally not exposed here.

Signature

ts
type AgentToolOutcome = AgentToolFailure | AgentToolSuccess;

AgentToolSuccess#

Public projection of a successful mutation-backed tool execution.

Signature

ts
interface AgentToolSuccess {
  readonly ok: true;
  readonly value: unknown;
}

AgentTurnResult#

One mediated model output or mutation-backed tool result, with the retained integrity.

Signature

ts
type AgentTurnResult =
  | {
      readonly integrity: AgentIntegrity;
      readonly kind: 'output';
      readonly offeredTools: readonly string[];
      readonly value: unknown;
    }
  | {
      readonly integrity: AgentIntegrity;
      readonly kind: 'tool-result';
      readonly offeredTools: readonly string[];
      readonly result: AgentToolOutcome;
      readonly tool: string;
    };

CreateAgentSessionOptions#

Options that pin a request principal before any model-selected effect can run.

Signature

ts
interface CreateAgentSessionOptions<
  Request extends object,
  SessionValue = unknown,
  DbValue = unknown,
> {
  clientIp?: (request: Request) => string | undefined;
  db?: AppDbProvider<DbValue>;
  onError?: ServerErrorHandler;
  onSessionSetCookie?: (rawSetCookie: string) => void;
  request: Request;
  sessionProvider?: SessionProvider<Request, SessionValue>;
}

@kovojs/server/build#

Task: Build-time deployment presets and neutral artifact helpers for kovo build.

Source: packages/server/src/build.ts

Values#

defineConfig#

Type helper for authoring kovo.config.ts without changing runtime behavior.

Signature

ts
function defineConfig(config: KovoConfig): KovoConfig;

node#

Create the built-in Node/VPS preset descriptor.

The emitted output wraps the neutral server/handler.mjs Request-to-Response contract in a Node http server and serves immutable /c/* plus hashed /assets/* client files without Vite at request time.

Signature

ts
function node(options: NodePresetOptions = {}): KovoPreset<'node'>;

vercel#

Create the built-in Vercel preset descriptor.

The emitted output follows Vercel Build Output API v3: static client files land under .vercel/output/static, and the request handler is wrapped as a Node.js Vercel Function under .vercel/output/functions/kovo.func.

Signature

ts
function vercel(options: VercelPresetOptions = {}): KovoPreset<'vercel'>;

cloudflare#

Create the built-in Cloudflare Workers preset descriptor.

The emitted output is a Wrangler project with a module Worker, static assets binding, and nodejs_compat enabled for the current Node-first request path.

Signature

ts
function cloudflare(options: CloudflarePresetOptions = {}): KovoPreset<'cloudflare'>;

Supporting types#

KovoPreset#

Opaque framework-owned deployment preset selected by kovo build.

Preset emission, inspection, and capability descriptors are intentionally not public. Create a value only through node(), vercel(), or cloudflare(); app-authored structural preset objects are rejected by the build preflight (SPEC §5.2 and §9.6).

Signature

ts
interface KovoPreset<
  Name extends 'cloudflare' | 'node' | 'vercel' = 'cloudflare' | 'node' | 'vercel',
> {
  readonly [kovoPresetTypeBrand]: Name;
}

DeploySkewRetentionProof#

Deployment-owned proof that the serving layer satisfies SPEC §14 for long-lived documents.

Kovo can emit immutable /c/__v/... modules and token-tagged reads, but only the deploy layer can prove prior builds stay reachable across redeploys. The window is configurable upward; SPEC §14 makes 24 hours the minimum floor.

Signature

ts
interface DeploySkewRetentionProof {
  /** Supported wall-clock deploy-skew window. Must be at least 24 hours. */
  hours: number;
  /** Prior immutable `/c/__v/...` client modules remain reachable for the window. */
  immutableClientModules: 'retained';
  /** Prior-token `/_q/<key>` reads remain reachable for the window. */
  priorTokenQueryReads: 'retained';
}

DeploySkewPresetOptions#

Shared deploy-skew options accepted by built-in build presets.

Signature

ts
interface DeploySkewPresetOptions {
  /** Serving-layer retention proof for SPEC §14 deploy-skew recovery. */
  retention?: DeploySkewRetentionProof;
}

NodePresetOptions#

Options for the built-in Node/VPS preset.

Signature

ts
interface NodePresetOptions extends DeploySkewPresetOptions {
  /** Whether the node preset emits a minimal Dockerfile next to `server.mjs`; defaults to true. */
  dockerfile?: boolean;
  /** Durable task runner mode; defaults to the in-process serve-and-run JobRunner. */
  jobRunner?: NodeJobRunnerOptions | false;
}

NodeJobRunnerOptions#

Node preset durable task runner options (SPEC §9.6).

Signature

ts
interface NodeJobRunnerOptions {
  /**
   * `serve-and-run` drains jobs inside the HTTP process. `runner-only` is reserved until the neutral
   * server bundle exposes a runner entrypoint; selecting it currently fails closed at build time.
   */
  mode?: 'serve-and-run' | 'runner-only';
}

VercelPresetOptions#

Options for the built-in Vercel preset.

Signature

ts
interface VercelPresetOptions extends DeploySkewPresetOptions {
  /** Maximum Vercel Function duration in seconds. */
  maxDuration?: number;
  /** Vercel Function memory in MB. */
  memory?: number;
  /** Vercel regions for the Node function. */
  regions?: readonly string[];
}

CloudflarePresetOptions#

Options for the built-in Cloudflare Workers preset.

Signature

ts
interface CloudflarePresetOptions extends DeploySkewPresetOptions {
  /** Worker compatibility date; defaults to the first date that supports `nodejs_compat` v2. */
  compatibilityDate?: string;
  /** Generated Worker name in `wrangler.toml`; defaults to `kovo-app`. */
  name?: string;
}

KovoConfig#

Build-time project configuration loaded from kovo.config.ts.

Signature

ts
interface KovoConfig {
  /** Platform preset used by `kovo build` when CLI/env overrides are absent. */
  readonly preset?: KovoPreset;
}

@kovojs/server/client-modules#

Task: Versioned client-module registries and storage contracts.

Source: packages/server/src/public-client-modules.ts

Values#

createMemoryVersionedClientModuleRegistry#

Create the default in-memory representation store. This store is useful in development and for build assembly, but does not by itself prove SPEC §14 restart/replica retention.

Signature

ts
function createMemoryVersionedClientModuleRegistry(
  options: MemoryVersionedClientModuleRegistryOptions = {},
): VersionedClientModuleRegistry;

Supporting types#

MemoryVersionedClientModuleRegistryOptions#

Options for the in-memory store. Count-based retention remains an explicit KV417 refusal.

Signature

ts
interface MemoryVersionedClientModuleRegistryOptions {
  /** @deprecated Count-based eviction cannot prove SPEC §14's 24-hour restart/replica floor. */
  maxVersionsPerPath?: number;
}

VersionedClientModuleActiveSnapshot#

Durable exact active deployment snapshot stored by a client-module store (SPEC §5.2.1/§14). The framework derives every href and the app-build token from these raw inputs.

Signature

ts
interface VersionedClientModuleActiveSnapshot {
  modules: readonly VersionedClientModuleInput[];
  renderPlanFingerprint: string;
}

VersionedClientModuleInput#

Source representation accepted by framework-owned client-module storage (SPEC §5.2.1/§14).

Signature

ts
interface VersionedClientModuleInput {
  path: string;
  source: string;
}

VersionedClientModuleRegistry#

Framework facade used by the request shell after closing an injected store.

Signature

ts
interface VersionedClientModuleRegistry {
  /** Frozen, eagerly derived app-build token. This call never hashes or mutates storage. */
  buildToken(): string;
  /** Exact current active set; retained resolver history is excluded. */
  entries(): readonly VersionedClientModuleInput[];
  /** Stage a stable/manual module using a framework-derived immutable href. */
  put(module: VersionedClientModuleInput): string;
  /** Resolve and re-verify one immutable representation through the closed store. */
  resolve(href: string): ServerResponseBase<string, Record<string, string>, 200 | 404>;
}

VersionedClientModuleStore#

App/deployment storage contract. Immutable representation retention and active-snapshot publication are deliberately separate: replaceActiveSnapshot() MUST atomically replace the durable exact active set, while resolve() continues to serve retained history for the §14 skew window. The store never supplies an href, digest, or app-build token (SPEC §5.2.1/§14).

Signature

ts
interface VersionedClientModuleStore {
  readActiveSnapshot(): VersionedClientModuleActiveSnapshot;
  replaceActiveSnapshot(snapshot: VersionedClientModuleActiveSnapshot): void;
  retain(module: VersionedClientModuleInput): void;
  resolve(href: string): ServerResponseBase<string, Record<string, string>, 200 | 404>;
}

@kovojs/server/command#

Task: Allowlisted operating-system command construction and execution.

Source: packages/server/src/public-command.ts

Values#

cmd#

Create a framework-owned, shell-free command capability.

SPEC §6.6 / KV424 and plans/most-secure-web-framework.md SINK-02: this is a runtime-DiD floor plus a type-only surface, not a proof that raw child_process imports elsewhere are impossible. The only execution helper Kovo exposes for this value uses execFile(..., { shell: false }).

Signature

ts
function cmd(program: string, argv: readonly string[], options: CommandOptions): Command;

commandAllowlist#

Declare the exact absolute executable paths a command boundary may run.

SPEC §6.6 / KV424: subprocess execution is default-deny for framework/runtime paths. A command is mintable only when its program is present in this explicit allowlist and the allowlist carries an audit-readable justification.

Signature

ts
function commandAllowlist(
  programs: readonly string[],
  options: { justification: string },
): CommandAllowlist;

runCommand#

Execute a shell-free command minted by {@link cmd}.

The runtime witness is re-checked here so any casts or structurally forged objects fail closed before reaching child_process.execFile.

Signature

ts
function runCommand(
  command: Command,
  options: CommandRunOptions = {},
): Promise<CommandResult>;

Supporting types#

Command#

A shell-free command minted by {@link cmd}.

Signature

ts
interface Command {
  /** Absolute normalized executable path passed as `file` to `child_process.execFile`. */
  readonly program: string;
  /** Arguments passed as the `args` array to `child_process.execFile`. */
  readonly argv: readonly string[];
  readonly [commandBrand]: true;
}

CommandAllowlist#

Explicit allowlist required before a program can become an executable command.

Signature

ts
interface CommandAllowlist {
  /** Human-reviewable reason this process boundary exists. */
  readonly justification: string;
  readonly [commandAllowlistBrand]: true;
}

CommandOptions#

Options for constructing a shell-free {@link Command}.

Signature

ts
interface CommandOptions {
  /** Explicit set of executable programs allowed at this command boundary. */
  readonly allow: CommandAllowlist;
}

CommandResult#

Completed stdout/stderr from a shell-free {@link Command}.

Signature

ts
interface CommandResult {
  readonly stderr: string;
  readonly stdout: string;
}

CommandRunOptions#

Options for executing a shell-free {@link Command}.

Signature

ts
interface CommandRunOptions {
  /** Absolute normalized working directory for the child process. */
  cwd?: string;
  /** Maximum bytes buffered for stdout/stderr. Defaults to Node's `execFile` default. */
  maxBufferBytes?: number;
  /** Abort signal forwarded to `execFile`. */
  signal?: AbortSignal;
  /** Timeout in milliseconds before Node terminates the child process. */
  timeoutMs?: number;
}

@kovojs/server/confidential#

Task: Confidential-at-rest encryption, decryption, and key rewrapping.

Source: packages/server/src/public-confidential.ts

Values#

createConfidentialAtRestCipher#

Bind an exact root-key ring to one confidential destination.

The returned carrier has no methods or key metadata. Only the fixed encrypt/decrypt/rewrap sinks can recover its purpose-scoped AES authority (SPEC §6.6 / OPP-04).

Signature

ts
function createConfidentialAtRestCipher(
  ring: SigningKeyRing,
  options: ConfidentialAtRestCipherOptions,
): ConfidentialAtRestCipher;

decryptAtRest#

Open a v2 envelope with its named active or unexpired previous key.

Unknown, revoked, expired, malformed, and unauthenticated envelopes intentionally share one externally visible failure (SPEC §6.6).

Signature

ts
function decryptAtRest(
  envelope: EncryptedAtRest | string,
  cipher: ConfidentialAtRestCipher,
  options: DecryptAtRestOptions = {},
): Uint8Array;

encryptAtRest#

Seal plaintext with the ring's sole active key into the normative v2 envelope.

Signature

ts
function encryptAtRest(
  plaintext: string | Uint8Array,
  cipher: ConfidentialAtRestCipher,
  options: EncryptAtRestOptions = {},
): EncryptedAtRest;

rewrapAtRest#

Open with an eligible old key and immediately reseal under the active key.

Signature

ts
function rewrapAtRest(
  envelope: EncryptedAtRest | string,
  cipher: ConfidentialAtRestCipher,
  options: DecryptAtRestOptions = {},
): EncryptedAtRest;

Supporting types#

ConfidentialAtRestCipher#

Opaque framework-minted confidential-at-rest authority carrier.

Signature

ts
interface ConfidentialAtRestCipher {
  readonly [confidentialAtRestCipherBrand]: 'kovo-confidential-at-rest-cipher';
}

ConfidentialAtRestCipherOptions#

Fixed authenticated destination for a confidential-at-rest cipher.

Signature

ts
interface ConfidentialAtRestCipherOptions {
  /** Destination identity, such as `users.ssn`; folded into HKDF and AES-GCM AAD. */
  readonly audience: string;
}

DecryptAtRestOptions#

Caller context required to open a confidential-at-rest envelope.

Signature

ts
type DecryptAtRestOptions = EncryptAtRestOptions;

EncryptedAtRest#

A compact versioned AES-256-GCM envelope produced by {@link encryptAtRest}.

Signature

ts
type EncryptedAtRest = string & { readonly __kovoEncryptedAtRest: unique symbol };

EncryptAtRestOptions#

Caller context additionally authenticated by the confidential-at-rest sink.

Signature

ts
interface EncryptAtRestOptions {
  /** Optional record/tenant context. The destination audience is always authenticated. */
  readonly aad?: string | Uint8Array;
}

@kovojs/server/custom-adapters#

Task: Opaque app tokens and request handlers for custom server integrations.

Source: packages/server/src/public-custom-adapters.ts

Values#

createRequestHandler#

Turn a KovoApp into a Web-standard request handler after runtime bootstrap.

Custom entries must import @kovojs/server/runtime-bootstrap as their literal first import on every supported runtime. Generated Kovo runners install the same lock automatically. The handler refuses to start without that ordering proof because classifier-reviewed globals otherwise remain caller-mutable (SPEC §6.6/§9.5).

Parameter Type Description
app KovoApp Opaque app token returned by app.assemble().
(returns) RequestHandler A bootstrapped request handler suitable for the platform adapter.

Signature

ts
function createRequestHandler(app: KovoApp): RequestHandler;

Supporting types#

KovoApp#

Opaque application token returned by app.assemble() (SPEC §6.2.1/§9.5).

Runtime providers, registries, declarations, and framework authorities live in a module-private WeakMap. The private symbol is an author-time guardrail only; exact map membership is the runtime proof.

Signature

ts
interface KovoApp<AppTypes = unknown> {
  readonly [kovoAppTokenBrand]: AppTypes;
}

InferKovoAppTypes#

Extract the author-usable contract and exact declaration-handle unions retained by an opaque {@link KovoApp}. Runtime providers, registries, and assembly arrays are deliberately absent.

Signature

ts
type InferKovoAppTypes<App extends KovoApp> =
  App extends KovoApp<infer AppTypes> ? AppTypes : never;

AppMutationAdapter#

Opaque framework-adapter mutation accepted by app.integrateMutation().

Ordinary app writes use app.mutation({ ... }). This capability exists for reviewed framework adapters, such as Better Auth credential mutations, whose fixed identity and private authority must survive app assembly (SPEC §6.2.1/§6.6).

Signature

ts
type AppMutationAdapter<Definition extends { key: string } = { key: string }> =
  Definition & {
    readonly [appMutationAdapterBrand]: 'kovo.app-mutation-adapter';
  };

RequestHandler#

Web-standard request handler returned by createRequestHandler() (SPEC §9.5).

Signature

ts
type RequestHandler = (request: Request) => Promise<Response>;

@kovojs/server/data#

Task: Managed-data read declarations, invalidation records, and cache influences.

Source: packages/server/src/public-data.ts

Values#

declarePublicRead#

Declare an audited public-read authorization scope (SPEC §10.3 DEC-F). This does not assert SQL injection safety (trustedSql) or secret disclosure authority (reveal); it only records the intentional row/column authorization posture for a read.

Signature

ts
function declarePublicRead(options: PublicReadDeclaration): PublicReadDeclaration;

readonlyDb#

Create the public read-only managed DB handle with its Node parser authority preloaded (SPEC §6.6 rule 6, §9.4, §10.3).

Keeping this explicit wrapper separate lets route-only/Cloudflare bundles discard the Node VM branch when readonlyDb is not used. A retained managed-DB export evaluates its trusted parser bootstrap before authored app code and also asserts readiness at construction.

Signature

ts
function readonlyDb<Db extends object>(
  db: Db,
  options: { crossOwnerRead?: CrossOwnerReadPolicyOptions; rawRead?: RawReadPolicyOptions } = {},
): Reader<Db>;

Supporting types#

CrossOwnerReadDeclaration#

User-authored declaration for the audited cross-owner read escape (SPEC §10.3 DEC-G).

Signature

ts
interface CrossOwnerReadDeclaration {
  /** Required audit reason explaining why this endpoint may read across owners. */
  reason: string;
  /** Physical table set the statement may read. The v1 runtime supports a single owner table. */
  reads: readonly string[];
  /** Runtime role gate. Only an admin-guarded call may request this capability. */
  role: 'admin';
  /** Optional source span for capability ledgers. */
  site?: string;
}

CrossOwnerReadPolicyOptions#

Framework-owned cross-owner read execution options.

Signature

ts
interface CrossOwnerReadPolicyOptions {
  adminClient?: object;
  /** Exact SQL dialect used by the fail-closed read classifier. */
  dialect: 'postgres' | 'sqlite';
  dialectLabel: string;
  executeSql?: (statement: { params: readonly unknown[]; text: string }) => unknown;
  executeMethod?: 'all' | 'execute' | 'query' | 'values';
  hasRole?: (role: CrossOwnerReadDeclaration['role']) => boolean;
  normalizeTableName: (table: string) => string;
  ownerTables: readonly string[];
  principal?: string | undefined;
}

DeclaredWriteSqliteAuthorizerConstants#

Framework-owned SQLite authorizer constants supplied by the runtime's SQLite engine.

Signature

ts
interface DeclaredWriteSqliteAuthorizerConstants {
  SQLITE_ALTER_TABLE: number;
  SQLITE_ATTACH: number;
  SQLITE_CREATE_INDEX: number;
  SQLITE_CREATE_TABLE: number;
  SQLITE_CREATE_TEMP_INDEX: number;
  SQLITE_CREATE_TEMP_TABLE: number;
  SQLITE_CREATE_TEMP_TRIGGER: number;
  SQLITE_CREATE_TEMP_VIEW: number;
  SQLITE_CREATE_TRIGGER: number;
  SQLITE_CREATE_VIEW: number;
  SQLITE_CREATE_VTABLE: number;
  SQLITE_DELETE: number;
  SQLITE_DENY: number;
  SQLITE_DETACH: number;
  SQLITE_DROP_INDEX: number;
  SQLITE_DROP_TABLE: number;
  SQLITE_DROP_TEMP_INDEX: number;
  SQLITE_DROP_TEMP_TABLE: number;
  SQLITE_DROP_TEMP_TRIGGER: number;
  SQLITE_DROP_TEMP_VIEW: number;
  SQLITE_DROP_TRIGGER: number;
  SQLITE_DROP_VIEW: number;
  SQLITE_DROP_VTABLE: number;
  SQLITE_INSERT: number;
  SQLITE_OK: number;
  SQLITE_PRAGMA: number;
  SQLITE_READ?: number;
  SQLITE_REINDEX: number;
  SQLITE_UPDATE: number;
}

DeclaredWriteSqliteAuthorizerDatabase#

Framework-owned structural SQLite authorizer database handle.

Signature

ts
interface DeclaredWriteSqliteAuthorizerDatabase {
  close(): void;
  prepare(statement: string): unknown;
  setAuthorizer(
    callback: (
      action: number,
      objectName: string | null,
      columnName: string | null,
      databaseName: string | null,
      triggerOrView: string | null,
    ) => number,
  ): void;
}

DeclaredWriteSqliteAuthorizerOptions#

SQLite engine mechanism options for {@link createDeclaredWriteDb}.

Signature

ts
interface DeclaredWriteSqliteAuthorizerOptions {
  constants: DeclaredWriteSqliteAuthorizerConstants;
  openDatabase(): DeclaredWriteSqliteAuthorizerDatabase;
}

PublicReadDeclaration#

User-authored public-read authorization escape, distinct from SQL trust and secret reveal.

Signature

ts
interface PublicReadDeclaration {
  /** Columns intentionally exposed by the public read; omitted only when the projection is public. */
  columns?: readonly string[];
  /** Required audit reason explaining why this read is public. */
  reason: string;
  /** Row predicate or structured row-scope metadata that makes the read public. */
  rows?: PublicReadRowsScope | string;
}

PublicReadRowsScope#

Row-scope metadata for an audited public raw read (SPEC §10.3 DEC-F).

Signature

ts
interface PublicReadRowsScope {
  /** Audit-readable public predicate, for example `published = true`. */
  predicate: string;
  /** Optional physical table the predicate applies to when the raw read spans multiple reads. */
  table?: string;
}

RawReadDeclaration#

User-authored declaration for the raw read escape (SPEC §10.2/§10.3 DEC-C).

Signature

ts
interface RawReadDeclaration {
  actAs?: string;
  declarePublicRead?: PublicReadDeclaration;
  reads: readonly string[];
}

RawReadPolicyOptions#

Framework-owned rawRead enforcement options for a managed read handle.

Signature

ts
interface RawReadPolicyOptions {
  /** Exact SQL dialect used by the fail-closed read classifier. */
  dialect: 'postgres' | 'sqlite';
  dialectLabel: string;
  executeSql?: (statement: { params: readonly unknown[]; text: string }) => unknown;
  executeMethod?: 'all' | 'execute' | 'query' | 'values';
  normalizeTableName: (table: string) => string;
  ownerTables?: readonly string[];
  sqliteAuthorizer?: DeclaredWriteSqliteAuthorizerOptions;
}

Reader#

The compile-time mirror of the runtime read-only proxy (SPEC §9.4 KV433). Framework-owned read surfaces receive Reader<Db> so a db.insert(...) is a tsc error in addition to the runtime throw and the static gate. The private-symbol brand makes a raw provider handle awkward to pass where a framework-threaded read capability is expected.

This is ergonomics and defense-in-depth only (SPEC §6.6): the runtime proxy is the fail-closed floor, and the static KV433 provenance gate remains the by-construction proof. Casts/any can defeat this type and must never be accepted as security evidence.

Signature

ts
type Reader<Db> = (Db extends object
  ? Pick<Db, Extract<keyof Db, '$count' | '$with' | 'select' | 'selectDistinct'>> &
      (Db extends { query: infer Query }
        ? Query extends (...args: any[]) => any
          ? {}
          : { query: Query }
        : {}) & {
        crossOwnerRead<Row = unknown>(
          statement: unknown,
          declaration: CrossOwnerReadDeclaration,
        ): Promise<Row[]> | Row[];
        rawRead<Row = unknown>(
          statement: unknown,
          declaration: RawReadDeclaration,
        ): Promise<Row[]> | Row[];
      } & (Db extends { with: (...args: infer Args) => infer Result }
        ? {
            with(
              ...args: Args
            ): Result extends object
              ? Pick<
                  Result,
                  Extract<keyof Result, '$count' | '$with' | 'query' | 'select' | 'selectDistinct'>
                >
              : Result;
          }
        : {})
  : Db) & {
  readonly [readerDbBrand]: {
    readonly db: Db;
    readonly scope: 'framework-read-handle';
  };
};

Writer#

The compile-time mirror of a framework-threaded write handle (SPEC §10.3/§11.2, DEC-E). Unlike {@link Reader}, this keeps the underlying DB surface intact, but adds a private-symbol witness so APIs that require a managed write capability cannot be satisfied by a raw provider handle by accident. Runtime SQL/read-write enforcement still belongs to {@link managedDb} and {@link wrapManagedDbForSqlSafety}; this type is an author-time guardrail only.

Signature

ts
type Writer<Db> = Db & {
  readonly [writerDbBrand]: {
    readonly db: Db;
    readonly scope: 'framework-write-handle';
  };
};

AppDbProvider#

Opaque framework-owned DB provider token.

The token carries the lifecycle DB type for createApp({ db }) inference without exposing a callable that claims to return a raw database. Framework packages register its resolver in a private WeakMap; casts or structurally similar objects cannot mint a working provider.

Signature

ts
interface AppDbProvider<DbValue> {
  readonly [frameworkManagedDbProviderBrand]: (value: DbValue) => DbValue;
}

QueryReadConfig#

Explicit cache posture for proven public, session-independent typed reads (SPEC §9.4).

Signature

ts
interface QueryReadConfig {
  /** Compiler-reviewed inputs and version-key obligations for an explicitly public response. */
  cacheInfluence?: SharedCacheInfluenceDeclaration;
  cacheControl?: string;
}

ChangeRecord#

A record of one domain a mutation touched, optionally scoped to specific keys.

Signature

ts
interface ChangeRecord<DomainKey extends string = string, Input = unknown> {
  /**
   * The touched domain spans multiple tables (parent+child / relational), so `keys`
   * are in the mutated table's identity space — NOT necessarily the canonical
   * single-row identity space a reader is instance-keyed by. When set, a key-scoped
   * change is NOT proof of single-row identity, so every reader of the domain reruns
   * (SPEC §10.1: over-invalidate when row identity is uncertain; bugz-3 M9).
   */
  crossTable?: true;
  domain: DomainKey;
  keys?: readonly string[];
  input?: Input;
  manual?: true;
  reason?: string;
  via?: string;
}

InvalidateOptions#

Options for invalidate/context.invalidate: row keys, input echo, and a reason.

Signature

ts
interface InvalidateOptions<Input = unknown> {
  input?: Input;
  keys?: readonly string[];
  reason?: string;
}

SharedCacheExternalDataVersion#

A versioned external data dependency and the cache-key dimension carrying its version.

Signature

ts
interface SharedCacheExternalDataVersion {
  readonly key: SharedCacheKeyContribution;
  readonly name: string;
}

SharedCacheInfluenceDeclaration#

Explicit source declaration consumed by the compiler's shared-cache generality proof. auditedEscape retains an operator obligation; it is never positive compiler evidence.

Signature

ts
interface SharedCacheInfluenceDeclaration {
  readonly auditedEscape?: {
    readonly name: string;
    readonly retainedObligation: string;
  };
  readonly externalDataVersions?: readonly SharedCacheExternalDataVersion[];
}

SharedCacheKeyContribution#

A request dimension that contributes an external data version to the shared-cache key.

Signature

ts
type SharedCacheKeyContribution =
  | { readonly axis: 'request-header'; readonly name: string }
  | { readonly axis: 'url-path' }
  | { readonly axis: 'url-search'; readonly name: string };

AppReadRequest#

Read-surface variant of an app lifecycle request. Query, layout, and route callbacks receive this shape from app-scoped createApp() authoring helpers: if a DB provider exists, request.db is a branded {@link Reader} whose write verbs are absent at author time and rejected by the runtime proxy (SPEC §6.6 / §10.2 / §10.3).

Signature

ts
type AppReadRequest<Request> = Request extends { db: infer DbValue }
  ? Omit<Request, 'db'> & { db: Reader<DbValue> }
  : Request;

@kovojs/server/delegation#

Task: Principal delegation authorities and on-behalf-of execution.

Source: packages/server/src/public-delegation.ts

Values#

createDelegationAuthority#

Bridge a guard/RLS-authorized root into the attenuating delegation algebra (SPEC §10.3).

This constructor never grants database authority: it records the exact right set a caller says its existing policy established. Widening grant-table writes remain named, budgeted escapes in kovo explain grants; downstream engine policy remains the enforcement boundary.

Signature

ts
async function createDelegationAuthority<const Rights extends readonly DelegationRight[]>(
  options: CreateDelegationAuthorityOptions<Rights>,
): Promise<DelegationAuthority<Rights[number]>>;

onBehalfOf#

Delegate a subset of an existing authority and re-witness its persistent principal epoch.

Both TypeScript and the runtime subset test reject widened child sets. The authoritative epoch lookup has no positive cache, so role/tenant/admin revocation invalidates the complete chain.

Signature

ts
async function onBehalfOf<
  ParentRight extends DelegationRight,
  const Rights extends readonly ParentRight[],
>(
  parent: DelegationAuthority<ParentRight>,
  options: OnBehalfOfOptions<Rights>,
): Promise<DelegationAuthority<Rights[number]>>;

Supporting types#

CreateDelegationAuthorityOptions#

Options for the root bridge from already-proven guard/RLS authority into delegation.

Signature

ts
interface CreateDelegationAuthorityOptions<
  Rights extends readonly DelegationRight[] = readonly DelegationRight[],
> {
  /** Exact currently acting principal. This constructor does not itself prove an app policy. */
  readonly actor: string;
  /** Revocation identity whose persistent epoch binds every descendant. */
  readonly principal: string;
  readonly principalEpochStore: PrincipalEpochStore;
  /** Rights already established by the caller's guard/RLS door. */
  readonly rights: Rights;
}

DelegationAuthority#

Immutable, framework-receipted attenuating authority (SPEC §10.3).

The public fields are explainable evidence, not the runtime proof. Runtime consumers verify the module-private receipt and current principal epoch; structural casts do not mint authority.

Signature

ts
interface DelegationAuthority<Right extends DelegationRight = DelegationRight> {
  readonly [delegationAuthorityBrand]: {
    readonly scope: 'framework-owned-delegation-authority';
  };
  readonly actor: string;
  readonly onBehalfOf: string;
  readonly principalEpoch: number;
  readonly rights: readonly Right[];
}

DelegationRight#

A right names both its finite kind and exact compiler-derived resource vocabulary.

Signature

ts
type DelegationRight<Resource extends string = string> =
  `${DelegationRightKind}:${Resource}`;

DelegationRightKind#

Right kinds admitted by the finite grant model (SPEC §10.3).

Signature

ts
type DelegationRightKind =
  | 'delegate'
  | 'delegated-owner'
  | 'owner'
  | 'policy'
  | 'read'
  | 'write';

OnBehalfOfOptions#

Options for one strict-subset-or-equal delegation step.

Signature

ts
interface OnBehalfOfOptions<Rights extends readonly DelegationRight[]> {
  readonly actor: string;
  readonly rights: Rights;
}

@kovojs/server/derived-data#

Task: Derived vector dataset declarations and storage adapters.

Source: packages/server/src/public-derived-data.ts

Values#

derived#

Construct the only supported door from owner-scoped database data to a vector/RAG store.

SPEC §6.6 and §10.3 C9: the physical artifact identity is reconstructed from the complete request-derived ScopedKey; an app cannot supply a namespace, principal id, or structural brand.

Signature

ts
function derived<Record, Query, Match>(
  adapter: DerivedVectorStoreAdapter<Record, Query, Match>,
  options: DerivedVectorDatasetOptions,
): DerivedVectorDataset<Record, Query, Match>;

Supporting types#

DerivedVectorDataset#

Framework-owned, principal-scoped vector/RAG dataset.

Every read and write requires the exact framework request carrier. The handle derives a fresh ScopedKey at each operation, so an artifact written for principal A cannot be queried by principal B even when both use the same logical key. The private brand is type-level ergonomics; the closure-owned adapter methods and runtime ScopedKey witness enforce the boundary.

Signature

ts
interface DerivedVectorDataset<Record, Query, Match> {
  readonly [derivedVectorDatasetBrand]: 'kovo-derived-vector-dataset';
  /** Query the vector namespace re-derived from this exact request principal. */
  query(request: unknown, query: Query): Promise<readonly Match[]>;
  /** Persist records under the vector namespace re-derived from this exact request principal. */
  upsert(request: unknown, records: readonly Record[]): Promise<void>;
}

DerivedVectorDatasetOptions#

Static construction options for a principal-scoped derived dataset.

Signature

ts
interface DerivedVectorDatasetOptions {
  /** Stable logical artifact key; Kovo combines it with the request principal's `ScopedKey`. */
  readonly key: string;
  /** The first shipped derived-data family is deliberately the finite vector/RAG case. */
  readonly kind: 'vector';
}

DerivedVectorQueryInput#

Input reconstructed by Kovo for one principal-scoped vector query.

Signature

ts
interface DerivedVectorQueryInput<Query> {
  /** Opaque physical namespace derived from the complete inherited `ScopedKey` frame. */
  readonly namespace: string;
  /** Adapter-specific vector query. It cannot select or replace the namespace. */
  readonly query: Query;
}

DerivedVectorStoreAdapter#

Deployment adapter consumed only by {@link derived}.

The adapter is trusted to implement its namespace argument faithfully. Kovo reconstructs that argument and never exposes a caller-selected namespace through the public dataset handle.

Signature

ts
interface DerivedVectorStoreAdapter<Record, Query, Match> {
  /** Search only the exact namespace supplied by Kovo. */
  readonly query: (
    input: DerivedVectorQueryInput<Query>,
  ) => Promise<readonly Match[]> | readonly Match[];
  /** Insert or replace records only in the exact namespace supplied by Kovo. */
  readonly upsert: (input: DerivedVectorUpsertInput<Record>) => Promise<void> | void;
}

DerivedVectorUpsertInput#

Input reconstructed by Kovo for one principal-scoped vector write.

Signature

ts
interface DerivedVectorUpsertInput<Record> {
  /** Opaque physical namespace derived from the complete inherited `ScopedKey` frame. */
  readonly namespace: string;
  /** Dense, bounded, immutable record-list snapshot. */
  readonly records: readonly Record[];
}

@kovojs/server/diagnostics#

Task: Application diagnostic and server error reporting contracts.

Source: packages/server/src/public-diagnostics.ts

Supporting types#

AppDiagnostic#

A compile/route-table diagnostic surfaced on a KovoApp (the diagnostics array returned by createApp). Carries the diagnostic code, message, source file, and optional severity/position so app tooling can report it (SPEC §9.5).

Signature

ts
interface AppDiagnostic extends RegisteredDiagnostic<DiagnosticCode> {
  fileName: string;
  help?: string;
  length?: number;
  start?: { column: number; line: number };
}

ErrorShellRenderer#

Render an app-provided 403, 404, or 500 shell response for request-shell errors (SPEC §9.5).

Signature

ts
type ErrorShellRenderer = (context: { request: Request; status: 403 | 404 | 500 }) =>
  | Exclude<ServerRenderable, Promise<unknown>>
  | {
      body: Exclude<ServerRenderable, Promise<unknown>>;
      headers?: AppResponseHeaders;
      status?: 403 | 404 | 500;
    }
  | Promise<
      | Exclude<ServerRenderable, Promise<unknown>>
      | {
          body: Exclude<ServerRenderable, Promise<unknown>>;
          headers?: AppResponseHeaders;
          status?: 403 | 404 | 500;
        }
    >;

ServerErrorDiagnosticContext#

Diagnostic context passed to a createApp({ onError }) {@link ServerErrorHandler} when a request-shell phase throws. operation names the failing phase and the optional fields carry whatever request/route/mutation/query identity is known for that phase (SPEC.md §9.2).

Signature

ts
interface ServerErrorDiagnosticContext {
  /**
   * Stable, bounded failure fact safe for terminal, JSON, GitHub, MCP, editor, and devtool
   * projection. The raw (secret-sanitized) exception remains the first server-only hook argument.
   *
   * The shape is written here rather than naming the core-internal carrier so this public
   * observability seam does not require app authors to import an internal package subpath.
   */
  failure: {
    readonly correlationId: string;
    readonly code:
      | 'KTB001'
      | 'KTB002'
      | 'KTB003'
      | 'KTB004'
      | 'KTB005'
      | 'KTB006'
      | 'KTB007'
      | 'KTB008';
    readonly operation:
      | 'app-request'
      | 'client-module'
      | 'error-shell'
      | 'mutation-handler'
      | 'mutation-render'
      | 'mutation-response-policy'
      | 'mutation-stream'
      | 'no-js-mutation-handler'
      | 'query-endpoint'
      | 'route-page'
      | 'route-render'
      | 'task-runner'
      | 'task-runtime-startup';
    readonly remediation: string;
    readonly safeCause:
      | 'client-module-resolution-failed'
      | 'error-shell-render-failed'
      | 'handler-execution-failed'
      | 'request-dispatch-failed'
      | 'response-policy-failed'
      | 'response-render-failed'
      | 'runtime-startup-failed'
      | 'task-execution-failed';
    readonly schema: 'kovo.trusted-boundary-failure/v1';
    readonly source?: {
      readonly end: number;
      readonly file: string;
      readonly start: number;
    };
    readonly sourceKind?: 'config' | 'source';
  };
  mutationKey?: string;
  taskJobId?: string;
  taskKey?: string;
  operation:
    | 'app-request'
    | 'client-module'
    | 'error-shell'
    | 'mutation-handler'
    | 'mutation-render'
    | 'mutation-response-policy'
    | 'mutation-stream'
    | 'no-js-mutation-handler'
    | 'query-endpoint'
    | 'route-page'
    | 'route-render'
    | 'task-runner'
    | 'task-runtime-startup';
  queryKey?: string;
  request?: unknown;
  routePath?: string;
  status?: 403 | 404 | 500;
  targets?: readonly string[];
  url?: string;
}

ServerErrorHandler#

Observability hook supplied to createApp({ onError }). Invoked when a request-shell phase throws, with a secret/URL-sanitized error and {@link ServerErrorDiagnosticContext}; it must not change the stable SPEC.md §9.2 server-error responses (errors thrown here are swallowed).

Signature

ts
type ServerErrorHandler = (
  error: unknown,
  context: ServerErrorDiagnosticContext,
) => Promise<void> | void;

EnvValidationIssue#

One field-level boot validation failure: a stable machine code, a human message, the dot-joined path locating it (e.g. csrf.secret or an app-env key), and whether it is fatal (refuses boot in production) or advisory (warn).

Signature

ts
interface EnvValidationIssue {
  /** Stable code so deploy tooling can match without parsing the message. */
  code: 'missing' | 'too-short' | 'low-entropy' | 'committed-secret' | 'invalid';
  /** Dot-joined location of the failure, e.g. `csrf.secret`. */
  path: string;
  /** Human-readable, actionable description of the failure and its fix. */
  message: string;
  /** When true, this issue refuses boot in production; when false it only warns. */
  fatal: boolean;
}

@kovojs/server/egress#

Task: Outbound network policy configuration and blocked-egress diagnostics.

Source: packages/server/src/public-egress.ts

Supporting types#

EgressBlockedError#

Thrown (502-class — the server could not complete an upstream call it was coaxed into) when the egress floor blocks an outbound connection to a private / loopback / link-local / metadata destination that is not permitted. The message names the destination and the remediation so an operator with a legitimate internal call can fix it in one step.

Signature

ts
class EgressBlockedError extends Error {
  override readonly name = EGRESS_BLOCKED_ERROR_NAME;
  /** The `host:port` (or `ip:port`) the connection was blocked from reaching. */
  readonly destination: string;
  /** The resolved IP the classifier rejected, when a literal/looked-up IP was available. */
  readonly resolvedIp: string | undefined;
  /** Coarse reason class for audit. */
  readonly classification: PrivateAddressClass;
  /** Which egress posture rejected the destination. */
  readonly reason:
    | 'private-network'
    | 'destination-allowlist'
    | 'missing-floor'
    | 'unix-domain-socket'
    | 'unconnected-datagram';
  /** Suggested HTTP status for adapters that surface this on the wire (SPEC §9.5). */
  readonly status = 502;

  constructor(args: {
    destination: string;
    resolvedIp?: string | undefined;
    classification: PrivateAddressClass;
    metadata?: boolean;
    reason?:
      | 'private-network'
      | 'destination-allowlist'
      | 'missing-floor'
      | 'unix-domain-socket'
      | 'unconnected-datagram'
      | undefined;
  }) {
    const where =
      args.resolvedIp && args.resolvedIp !== egressStringSplit(args.destination, ':')[0]
        ? `${args.destination} (resolved to ${args.resolvedIp})`
        : args.destination;
    const reason = args.reason ?? 'private-network';
    let remediation: string;
    if (reason === 'missing-floor') {
      remediation =
        'Install createApp({ egress }) / installEgressFloor() before invoking Kovo runtime egress.';
    } else if (reason === 'unix-domain-socket') {
      remediation =
        'Unix-domain sockets are default-denied because they can reach local privileged services; ' +
        'expose an explicitly governed TCP endpoint instead.';
    } else if (reason === 'unconnected-datagram') {
      remediation =
        'Connect the datagram socket before sending so Kovo can validate the kernel-pinned peer; ' +
        'unconnected per-send DNS cannot be pinned through the public Node UDP socket API.';
    } else if (reason === 'destination-allowlist') {
      remediation = 'Add the exact origin to createApp({ egress: { allowDestinations: [...] } }).';
    } else if (args.metadata) {
      remediation =
        'Cloud instance-metadata is reachable only inside an awsCredential()/gcpCredential()/' +
        'azureCredential() frame, never via egress.allowInternal.';
    } else {
      remediation =
        `If this internal destination is intended, add "${args.destination}" to ` +
        'createApp({ egress: { allowInternal: [...] } }).';
    }
    super(
      `Outbound egress to ${where} was blocked by the Kovo private-network deny floor ` +
        `(${args.classification}; SPEC §6.6 runtime defense-in-depth). ${remediation}`,
    );
    securityEvent({
      reason:
        reason === 'private-network'
          ? 'internal-network'
          : reason === 'unix-domain-socket' || reason === 'unconnected-datagram'
            ? 'malformed-destination'
            : 'policy',
      type: 'egress-denied',
    });
    // @kovo-security-denial egress-denied egress-blocked-error
    this.destination = args.destination;
    this.resolvedIp = args.resolvedIp;
    this.classification = args.classification;
    this.reason = reason;
  }
}

EgressConfigError#

Boot-time config error for an invalid/forbidden egress allowlist entry.

Signature

ts
class EgressConfigError extends Error {
  override readonly name = 'EgressConfigError';
  readonly entry: string;
  constructor(message: string, entry: string) {
    super(message);
    this.entry = entry;
  }
}

EgressOptions#

Operator-facing config (the egress field of createApp).

Signature

ts
interface EgressOptions {
  /**
   * Narrow `host:port` allowlist of internal destinations the app may reach despite the
   * deny floor — e.g. `['otel:4318', 'localhost:11434', '10.0.5.2:6379']`. `host:port`
   * entries only. A bare host or a CIDR is flagged and warned (broad CIDRs widen the hole);
   * the metadata endpoint can NEVER be allowlisted here.
   */
  allowInternal?: readonly string[];
  /**
   * Exact origin allowlist for framework-owned HTTP egress (`ctx.fetch` and future
   * webhook/agent-tool outbound helpers), e.g. `['https://api.stripe.com']`. This is a
   * positive destination allowlist: Kovo-owned runtime egress fails closed when omitted or
   * when the initial request or any redirect-hop origin is not listed. Private/internal origins also require
   * `allowInternal` because destination intent does not prove the resolved IP is safe.
   */
  allowDestinations?: readonly string[];
  /**
   * RFC 6052 Network-Specific Prefixes used by this deployment's DNS64/NAT64 translator.
   * Kovo already recognizes the well-known `64:ff9b::/96` prefix. List every additional
   * Pref64 as an IPv6 CIDR with one of RFC 6052's legal lengths: `/32`, `/40`, `/48`, `/56`,
   * `/64`, or `/96`. Prefixes are validated and snapshotted at boot; malformed, host-bit-set,
   * duplicate, or overlapping entries refuse boot instead of being ignored.
   */
  nat64Prefixes?: readonly string[];
  /**
   * Optional same-process tamper hardening for the transport monkeypatches.
   *
   * - `off` (default): only self-probes detect later monkeypatch drift.
   * - `warn`: installs warning setters around the net and datagram transport methods, so
   *   ordinary late reassignment is reported immediately. Undici global-dispatcher drift is
   *   still detected by self-probes because its ESM export cannot be frozen reliably here.
   * - `freeze`: makes the net-connect and datagram descriptors non-writable against ordinary
   *   reassignment.
   *
   * SPEC §6.6: this remains a runtime defense-in-depth floor, not sandbox protection.
   * Privileged same-process code can still bypass it with `defineProperty`, workers/children
   * need their own bootstrap, and native sockets are out of scope.
   */
  hardening?: 'off' | 'warn' | 'freeze';
}

PrivateAddressClass#

Coarse classification of a resolved destination address.

Signature

ts
type PrivateAddressClass =
  | 'public'
  | 'metadata'
  | 'loopback'
  | 'link-local'
  | 'private-rfc1918'
  | 'unique-local'
  | 'carrier-nat'
  | 'unspecified'
  | 'special-use';

AppEgressOptions#

createApp({ egress }) posture. Omit it to install the default floor; production uses an empty internal allowlist while development keeps local/private sidecars reachable except metadata. Pass an EgressOptions object to exercise exact allowlist semantics in any mode. Disable only through the audited { enabled: false, justification } escape.

Signature

ts
type AppEgressOptions = EgressOptions | AppEgressOptOut | false;

AppEgressOptOut#

Audited opt-out from the default-on outbound-egress private-network deny floor.

Signature

ts
interface AppEgressOptOut {
  enabled: false;
  /** Why this process intentionally serves without the SSRF egress floor (SPEC §6.6). */
  justification: string;
}

@kovojs/server/files#

Task: Root-confined filesystem access and file-serving options.

Source: packages/server/src/public-files.ts

Values#

rootedFiles#

Create a path-traversal-safe file serving primitive for a single filesystem root.

SPEC §6.6 / §9.1: raw file/path sinks must be routed through a safe framework surface. This primitive treats traversal, symlink escape, directories, missing files, and open races as generic not-found outcomes so callers do not branch on filesystem internals.

SPEC §14: a relative root is resolved against the process working directory in dev and at build time, and against the artifact's staged rooted/ copies in the generated production server — kovo build snapshots each relative root into the deploy artifact so the server never depends on files outside its own output. Absolute roots always name live deploy-host paths.

Signature

ts
async function rootedFiles(root: string): Promise<RootedFiles>;

Supporting types#

RootedFiles#

A framework-owned filesystem serving capability rooted at one real directory.

App code passes request-derived path segments to {@link RootedFiles.serve}; the primitive resolves through realpath containment before reading and returns the existing route response outcome instead of exposing the resolved filesystem path to app code.

Signature

ts
interface RootedFiles {
  readonly root: string;
  serve(path: string, options: RootedFileServeOptions): Promise<RouteResponseOutcome | undefined>;
}

RootedFileServeOptions#

Options for serving a file from a rooted filesystem capability.

Signature

ts
interface RootedFileServeOptions extends Omit<RouteStreamOptions, 'disposition'> {
  disposition?: 'attachment' | 'inline';
}

@kovojs/server/node#

Task: Node.js HTTP handler adapters.

Source: packages/server/src/public-node.ts

Values#

toNodeHandler#

Adapt a Web-standard RequestHandler (from createRequestHandler) to a Node http/https (req, res) listener, translating between Node and Web request/response objects.

Parameter Type Description
handler RequestHandler The Web request handler to adapt.
options NodeHandlerOptions Node adapter options (e.g. base URL resolution).
(returns) NodeRequestHandler A Node request listener.

Signature

ts
function toNodeHandler(
  handler: RequestHandler,
  options: NodeHandlerOptions = {},
): NodeRequestHandler;

Supporting types#

NodeHandlerOptions#

Options for adapting a Web RequestHandler to a Node http listener.

Signature

ts
interface NodeHandlerOptions {
  /** Compress eligible text responses by default; set `false` to opt out. */
  compression?: boolean;
  earlyHints?: boolean;
  /** One operator-pinned public origin. Per-request origin callbacks are intentionally unsupported. */
  origin?: string;
  /** Trust forwarded scheme headers when constructing Request URLs. Disabled by default. */
  trustedProxy?: boolean;
}

NodeRequestHandler#

Node http/https listener shape returned by toNodeHandler().

Signature

ts
type NodeRequestHandler = (
  request: IncomingMessage,
  response: ServerResponse,
) => Promise<void> | void;

@kovojs/server/password#

Task: Argon2id password hashing and credential verification.

Source: packages/server/src/public-password.ts

Values#

PASSWORD_ARGON2ID_DEFAULTS#

Default and minimum password hashing parameters. Kovo exposes no bcrypt, scrypt, SHA, or raw Argon2 algorithm knob; the sink always emits argon2id/v=19 PHC strings.

Signature

ts
const PASSWORD_ARGON2ID_DEFAULTS = passwordFreeze({
  memoryCost: 19 * 1024,
  timeCost: 2,
  parallelism: 1,
  outputLen: 32,
});

hashPassword#

Hash a plaintext password with Kovo's first-party argon2id-only sink.

SPEC §6.6: this is a runtime floor at the cryptographic sink, deliberately narrow. App code cannot select a fast hash or legacy verifier through this API.

Signature

ts
async function hashPassword(
  password: string | Uint8Array,
  options: PasswordHashOptions = {},
): Promise<PasswordDigest>;

isArgon2idPasswordDigest#

Runtime guard for stored digests accepted by {@link verifyPassword}.

Signature

ts
function isArgon2idPasswordDigest(digest: string): digest is PasswordDigest;

verifyCredential#

Verify a login credential while doing argon2id work even when the account is absent.

SPEC §6.6: this is a runtime defense-in-depth floor at the credential verification sink. Missing, malformed, or legacy stored digests verify against a framework-owned argon2id decoy digest derived from the call's resolved params, so absent-account work matches present-account work at any configured cost level and this helper boundary does not expose user existence through timing.

Signature

ts
async function verifyCredential(
  secret: string | Uint8Array,
  storedDigest: string | null | undefined,
  options: PasswordHashOptions = {},
): Promise<CredentialVerifyResult>;

verifyPassword#

Verify a plaintext password against a Kovo argon2id digest.

Non-argon2id, malformed, or legacy digests fail closed with { ok: false }; they are not passed through to the underlying library where bcrypt/scrypt/SHA-style fallback behavior could appear.

Signature

ts
async function verifyPassword(
  password: string | Uint8Array,
  digest: string,
  options: PasswordHashOptions = {},
): Promise<PasswordVerifyResult>;

Supporting types#

CredentialVerifyResult#

Result of verifying an account credential without exposing whether the account existed.

Signature

ts
interface CredentialVerifyResult {
  /** True only when a stored account digest exists, is accepted by Kovo, and the secret matches. */
  ok: boolean;
  /**
   * True when the credential verifies but uses weaker parameters than this call's configured floor.
   * Apps can use this to re-hash after successful login; Kovo does not mutate storage here.
   */
  needsRehash: boolean;
}

PasswordDigest#

Argon2id PHC digest produced by {@link hashPassword}.

This brand is an API chokepoint marker only. Per SPEC §6.6, password hashing is a runtime defense-in-depth floor at the hash/verify sink; it is not a proof of overall authentication strength and does not replace the future KV438 password-column write gate.

Signature

ts
type PasswordDigest = string & { readonly [passwordDigestBrand]: 'argon2id' };

PasswordHashOptions#

Argon2id parameters Kovo accepts for first-party password hashing.

Signature

ts
interface PasswordHashOptions {
  /**
   * Memory cost in KiB. Defaults to, and may not go below, 19 MiB (OWASP's Argon2id floor).
   */
  memoryCost?: number;
  /**
   * Iteration count. Defaults to, and may not go below, 2.
   */
  timeCost?: number;
  /**
   * Degree of parallelism. Defaults to, and may not go below, 1.
   */
  parallelism?: number;
  /**
   * Raw digest byte length before PHC encoding. Defaults to, and may not go below, 32.
   */
  outputLen?: number;
  /** Optional cancellation signal passed to the Argon2 worker. */
  signal?: AbortSignal;
}

PasswordVerifyResult#

Result of verifying a plaintext password against an argon2id digest.

Signature

ts
interface PasswordVerifyResult {
  /** True only when the digest is argon2id and the password matches. */
  ok: boolean;
  /**
   * True when the digest verifies but uses weaker parameters than this call's configured floor.
   * Apps can use this to re-hash after successful login; Kovo does not mutate storage here.
   */
  needsRehash: boolean;
}

@kovojs/server/postgres#

Task: Postgres provisioning, migration planning, posture checks, and runtime databases.

Source: packages/server/src/public-postgres.ts

Values#

checkPostgresAppDbPosture#

Check that an existing external Postgres database has the owner/RLS posture Kovo expects. This is the boot-time fail-closed check for managed Postgres.

Signature

ts
async function checkPostgresAppDbPosture(
  options: KovoPostgresAppRuntimeOptions,
): Promise<KovoPostgresPostureReport>;

createPostgresAppRuntimeDb#

Framework-owned Postgres runtime wiring for generated apps (SPEC §10.3).

The default no-env path keeps the technical-preview PGlite developer database. Setting KOVO_DATABASE_URL switches to an external Postgres pool whose boot path checks existing posture but does not create roles, tables, policies, or grants.

Signature

ts
function createPostgresAppRuntimeDb(
  options: KovoPostgresAppRuntimeOptions,
): KovoPostgresAppRuntimeDb;

declarePublicRelation#

Construct a reviewed public relation declaration for createPostgresAppRuntimeDb({ publicRelations }).

Signature

ts
function declarePublicRelation(
  options: KovoPostgresPublicRelationDeclarationOptions,
): KovoPostgresPublicRelationDeclaration;

migratePostgresAppDb#

Apply reviewed table-structure migrations, then re-derive and re-assert framework-owned Postgres RLS policies and grants (SPEC §10.3).

Signature

ts
async function migratePostgresAppDb(
  options: KovoPostgresMigrateOptions,
): Promise<KovoPostgresMigrationRunReport>;

planPostgresAppDbMigration#

Diff the current Postgres schema against the app Drizzle schema and emit a conservative, reviewable up/down migration (SPEC §10.3). This generator intentionally covers additive table and column changes only; destructive edits, renames, and data backfills stay hand-authored.

Signature

ts
async function planPostgresAppDbMigration(
  options: KovoPostgresMigrationPlanOptions,
): Promise<KovoPostgresMigrationPlan>;

postgresAppRuntimeOptions#

Capture generated Postgres runtime options through framework-owned intrinsics (SPEC §6.6/§10.3).

Generated modules call this instead of ambient Object.freeze(...). The constructor rejects Proxies, accessors, symbols, and unknown option keys; snapshots the schema and array-valued options; and returns an immutable null-prototype carrier. Runtime/provision/check consumers recover the module-private snapshot by carrier identity rather than re-reading app-held state. This authenticates the configuration carrier, not the safety of authored seedSql statements.

Parameter Type Description
options KovoPostgresAppRuntimeOptions Exact Postgres runtime options to pin before authored modules can mutate them.
(returns) Readonly<KovoPostgresAppRuntimeOptions> A frozen carrier assignable anywhere KovoPostgresAppRuntimeOptions is accepted.

Signature

ts
function postgresAppRuntimeOptions(
  options: KovoPostgresAppRuntimeOptions,
): Readonly<KovoPostgresAppRuntimeOptions>;

postgresSchemaModule#

Capture a genuine ESM schema namespace as one immutable own-data record.

Vite represents ESM live bindings as accessors, while the Postgres runtime deliberately rejects ordinary accessor-backed schema objects. This validating constructor accepts the immutable Module namespace shape emitted natively or by the production bundler, verifies each live binding is stable while captured, and returns the exact snapshot shared by runtime DDL/RLS and adapter construction (SPEC §6.6/§10.3).

Parameter Type Description
namespace Schema A namespace produced by import * as schema from './schema.js'.
(returns) Readonly<Schema> A frozen null-prototype record containing own data properties for every schema export.

Signature

ts
function postgresSchemaModule<Schema extends object>(namespace: Schema): Readonly<Schema>;

provisionPostgresAppDb#

Privileged provisioner for an external Postgres database. Run this from the CLI or deployment setup, not from ordinary app boot (SPEC §10.3).

Signature

ts
async function provisionPostgresAppDb(
  options: KovoPostgresProvisionOptions,
): Promise<KovoPostgresPostureReport>;

Supporting types#

KovoPostgresAppRuntimeDb#

Created app database runtime used by generated src/_kovo/app-runtime-db.ts modules.

Signature

ts
interface KovoPostgresAppRuntimeDb {
  /** Framework-system durable one-time capability replay truth (SPEC §6.6/§10.3). */
  readonly capabilityReplayStore: CapabilityReplayStore;
  /** Opaque framework provider token accepted by `createApp({ db })`. */
  readonly db: AppDbProvider<KovoPostgresRuntimeDb>;
  /** Framework-system durable mutation idempotency truth (SPEC §10.3). */
  readonly mutationReplayStore: MutationReplayStore;
  /** Framework-system persistent monotone principal revocation truth (SPEC §6.6/§10.3). */
  readonly principalEpochStore: PrincipalEpochStore;
  readonlyDb: Reader<KovoPostgresRuntimeDb>;
  ready: Promise<void>;
  /** Operator reconciliation for an exact crash-orphaned pending replay claim (SPEC §10.3). */
  releasePendingReplay(
    target: PostgresPendingReplayTarget,
    options: PostgresPendingReplayReleaseOptions,
  ): Promise<boolean>;
  /** Framework-system durable webhook idempotency truth (SPEC §10.3). */
  readonly webhookReplayStore: WebhookReplayStore;
  close(): Promise<void>;
}

KovoPostgresAppRuntimeOptions#

Configuration accepted by the generated app Postgres runtime helper.

Signature

ts
interface KovoPostgresAppRuntimeOptions {
  /**
   * The app schema module, usually `import * as schema from '../schema.js'`.
   * The runtime derives Postgres tables, DDL, RLS policies, and metadata from it.
   */
  schema: Record<string, unknown>;
  /** Override the persistent PGlite directory. Defaults to `KOVO_DATA_DIR` or `.kovo/pglite`. */
  dataDir?: string;
  /** Override the external Postgres URL. Defaults to `KOVO_DATABASE_URL`. */
  databaseUrl?: string;
  /**
   * Framework-owned external Postgres URL used only for audited `crossOwnerRead(...)` calls. The
   * login must be the configured `adminRole` or be able to `SET ROLE` to it; the ordinary app
   * runtime login must not be a member of that role (SPEC §10.3).
   */
  adminDatabaseUrl?: string;
  /**
   * Framework-owned external Postgres URL used only for audited system work. The login must be the
   * configured system role or be able to `SET ROLE` to it; the ordinary app runtime login must not
   * be a member of that role (SPEC §10.3).
   */
  systemDatabaseUrl?: string;
  /** Force the driver. Defaults to external Postgres when a database URL is present, PGlite otherwise. */
  driver?: KovoPostgresRuntimeDriver;
  /**
   * Run privileged provisioning during app boot. Defaults to true for PGlite and false for
   * external Postgres so production boot does not perform DDL/grants.
   */
  provisionOnBoot?: boolean;
  /**
   * Check schema/RLS/grant posture during app boot. Defaults to true for external Postgres and
   * false for PGlite because the default PGlite path provisions in-process first.
   *
   * Disabling the boot check is an audited capability escape: use
   * `postureCheck: { onBoot: false, justification: '...' }`, which is recorded for
   * `kovo explain capabilities`. Bare booleans are intentionally not accepted.
   */
  postureCheck?:
    | { readonly onBoot?: true }
    | { readonly justification: string; readonly onBoot: false; readonly site?: string };
  principalFromRequest?: (request: unknown) => string | undefined;
  readerRole?: string;
  /**
   * Role used by audited `crossOwnerRead(...)` calls. Defaults to `KOVO_DB_ADMIN_ROLE` or
   * `kovo_admin`; only used when `crossOwnerReadTables` is non-empty.
   */
  adminRole?: string;
  /**
   * Role used by audited system work. Defaults to `KOVO_DB_SYSTEM_ROLE` or `kovo_system`.
   * Supplying this option adopts a pre-created role instead of creating Kovo's default.
   */
  systemRole?: string;
  /** Physical owner/authz table names that should receive the per-table `kovo_admin_scope` policy. */
  crossOwnerReadTables?: readonly string[];
  /**
   * Reviewed database relations intentionally exposed as public read surfaces even though they
   * cannot prove Kovo row-level security, such as reporting materialized views (SPEC §10.3).
   * Use {@link declarePublicRelation}; plain objects are intentionally not accepted.
   */
  publicRelations?: readonly KovoPostgresPublicRelationDeclaration[];
  seedSql?: string | readonly string[];
  writerRole?: string;
}

KovoPostgresMigrateOptions#

Migration runner options for embedded PGlite or external Postgres.

Signature

ts
interface KovoPostgresMigrateOptions extends KovoPostgresAppRuntimeOptions {
  /** Reviewed SQL migrations to apply before Kovo reasserts RLS policies/grants. */
  migrations: readonly KovoPostgresMigration[];
  /** Least-privilege runtime URL whose login role receives app-role membership. */
  runtimeDatabaseUrl?: string;
}

KovoPostgresMigration#

One reviewed SQL migration file applied by the Postgres migration runner.

Signature

ts
interface KovoPostgresMigration {
  /** Stable migration id, usually the SQL file name. */
  id: string;
  /** SQL to apply transactionally. */
  sql: string;
}

KovoPostgresMigrationPlan#

One generated, reviewable Postgres migration plan.

Signature

ts
interface KovoPostgresMigrationPlan {
  /** Runtime driver used to inspect the current database. */
  driver: Exclude<KovoPostgresRuntimeDriver, 'pg'>;
  /** Reversible SQL for rolling back the generated additive changes. */
  downSql: string;
  /** True when the current database already matches the schema for supported additive changes. */
  empty: boolean;
  /** Human-readable summary of generated operations. */
  operations: readonly string[];
  /** Reviewable SQL to apply through `kovo db migrate`. */
  upSql: string;
}

KovoPostgresMigrationPlanOptions#

Options for planning an additive reviewed SQL migration from the current DB to schema.ts.

Signature

ts
interface KovoPostgresMigrationPlanOptions extends KovoPostgresAppRuntimeOptions {}

KovoPostgresMigrationRunReport#

Result of applying reviewed Postgres migrations before reasserting Kovo posture.

Signature

ts
interface KovoPostgresMigrationRunReport {
  applied: readonly string[];
  posture: KovoPostgresPostureReport;
  skipped: readonly string[];
}

KovoPostgresPostureIssue#

One failing Postgres schema/RLS/grant posture check.

Signature

ts
interface KovoPostgresPostureIssue {
  code: string;
  detail: string;
}

KovoPostgresPostureReport#

Result of checking an existing Postgres database against the app schema posture.

Signature

ts
interface KovoPostgresPostureReport {
  /**
   * Live policy activations derived from the same exact FORCE-RLS/policy-set posture check.
   * `verified` describes engine policy activation only; it does not claim guard/RLS equivalence.
   * SPEC §10.3.
   */
  authorizationPolicies: readonly {
    /** The closed framework SQL-emission site that generated this expected policy. */
    emissionSite: 'admin' | 'authzPolicy' | 'owner' | 'ownerVia' | 'system';
    /** The exact generated Postgres policy name. */
    policyName: 'kovo_admin_scope' | 'kovo_authz_policy' | 'kovo_owner_scope' | 'kovo_system_scope';
    /** The live relation schema checked through the engine catalog. */
    schemaName: string;
    /** Whether FORCE RLS and the table's complete expected policy set and shapes matched exactly. */
    status: 'unverified' | 'verified';
    /** The live relation name checked through the engine catalog. */
    tableName: string;
  }[];
  driver: Exclude<KovoPostgresRuntimeDriver, 'pg'>;
  ok: boolean;
  issues: readonly KovoPostgresPostureIssue[];
  roleTopology: {
    adminRole: {
      management: 'adopt' | 'create';
      name: string;
      purpose: 'admin' | 'reader' | 'system' | 'writer';
    };
    membershipEdges: readonly {
      memberRole: string;
      owner: 'dba' | 'kovo';
      role: string;
      status: 'expected' | 'granted' | 'missing' | 'verified';
    }[];
    readerRole: {
      management: 'adopt' | 'create';
      name: string;
      purpose: 'admin' | 'reader' | 'system' | 'writer';
    };
    runtimeLogin?: string;
    systemRole: {
      management: 'adopt' | 'create';
      name: string;
      purpose: 'admin' | 'reader' | 'system' | 'writer';
    };
    writerRole: {
      management: 'adopt' | 'create';
      name: string;
      purpose: 'admin' | 'reader' | 'system' | 'writer';
    };
  };
}

KovoPostgresProvisionOptions#

Privileged external Postgres provisioning options for the app schema.

Signature

ts
interface KovoPostgresProvisionOptions extends KovoPostgresAppRuntimeOptions {
  /**
   * Force a connection string for provisioning. This must be a privileged owner/admin connection
   * for external Postgres.
   */
  databaseUrl: string;
  /** Reviewed SQL migrations to apply before Kovo reasserts RLS policies/grants. */
  migrations?: readonly KovoPostgresMigration[];
  /** Least-privilege runtime URL whose login role receives app-role membership. */
  runtimeDatabaseUrl?: string;
}

KovoPostgresPublicRelationDeclaration#

Declare a vetted public Postgres relation for the boot-time closure audit (SPEC §10.3).

The declaration is the only supported escape for reachable relations that cannot carry Kovo RLS, such as materialized views. Base tables must use ordinary schema classifications (public, reference, owner, ownerVia, or authzPolicy) instead.

Signature

ts
interface KovoPostgresPublicRelationDeclaration extends KovoPostgresPublicRelationDeclarationOptions {
  /** Module-private witness so app config normally routes through declarePublicRelation(...). */
  readonly [publicPostgresRelationBrand]: {
    readonly scope: 'postgres-public-relation';
  };
}

KovoPostgresPublicRelationDeclarationOptions#

Options accepted by {@link declarePublicRelation}.

Signature

ts
interface KovoPostgresPublicRelationDeclarationOptions {
  /** Relation name, either `table_or_view_name` in `public` or `schema.table_or_view_name`. */
  relation: string;
  /** Required audit reason explaining why this relation is safe to expose publicly. */
  reason: string;
  /** Optional source span or config-site label surfaced in capability ledgers. */
  site?: string;
}

KovoPostgresRuntimeDb#

Drizzle database handle shape returned by the generated Postgres app runtime.

Signature

ts
type KovoPostgresRuntimeDb = PgliteDatabase | NodePgDatabase;

KovoPostgresRuntimeDriver#

Driver selector accepted by the generated app Postgres runtime.

Signature

ts
type KovoPostgresRuntimeDriver = 'node-postgres' | 'pglite' | 'pg';

@kovojs/server/principal-epochs#

Task: Principal epoch lifecycle and stale-principal enforcement.

Source: packages/server/src/public-principal-epochs.ts

Values#

advancePrincipalEpoch#

Framework/provider/OOB invalidation door for password, role, tenant, admin, and revocation events.

Signature

ts
async function advancePrincipalEpoch(
  store: PrincipalEpochStore,
  principal: string,
  reason: PrincipalEpochAdvanceReason,
): Promise<PrincipalEpochState>;

createMemoryPrincipalEpochStore#

Volatile development/test store with the same monotone and tombstone semantics as production.

Signature

ts
function createMemoryPrincipalEpochStore(
  options: { now?: () => number } = {},
): PrincipalEpochStore;

initializePrincipalEpoch#

Identity-provider lifecycle door. Atomically creates epoch 1 for a newly authenticated principal and otherwise returns the existing state without advancing it. A tombstone never reactivates.

Signature

ts
async function initializePrincipalEpoch(
  store: PrincipalEpochStore,
  principal: string,
): Promise<PrincipalEpochState>;

tombstonePrincipalEpoch#

Permanent principal deletion door. Tombstoned identities never verify again.

Signature

ts
async function tombstonePrincipalEpoch(
  store: PrincipalEpochStore,
  principal: string,
  reason: PrincipalEpochTombstoneReason,
): Promise<PrincipalEpochState>;

Supporting types#

PrincipalEpochStaleError#

The credential epoch no longer matches current persistent principal state.

Signature

ts
class PrincipalEpochStaleError extends Error {
  constructor() {
    super('Credential principal epoch is stale or tombstoned.');
    this.name = 'PrincipalEpochStaleError';
  }
}

PrincipalEpochUnavailableError#

Authoritative lookup failed, timed out, returned no row, or returned malformed state.

Signature

ts
class PrincipalEpochUnavailableError extends Error {
  constructor(
    message = 'Authoritative principal epoch state is unavailable.',
    options?: ErrorOptions,
  ) {
    super(message, options);
    this.name = 'PrincipalEpochUnavailableError';
  }
}

PrincipalEpochAdvanceReason#

Closed reasons accepted by the principal-epoch invalidation door.

Signature

ts
type PrincipalEpochAdvanceReason =
  | 'principal-created'
  | 'password-change'
  | 'role-change'
  | 'tenant-change'
  | 'admin-change'
  | 'provider-revocation'
  | 'manual-security-invalidation';

PrincipalEpochLookupOptions#

Cooperative lookup options. Stores should stop avoidable work when signal aborts.

Signature

ts
interface PrincipalEpochLookupOptions {
  readonly signal: AbortSignal;
}

PrincipalEpochState#

Persistent monotone state for one principal, independent of every session lifetime.

Signature

ts
interface PrincipalEpochState {
  /** Monotone epoch. A credential minted at any other value is stale. */
  readonly epoch: number;
  /** Authoritative change time used to reject idempotency tokens minted before a privilege change. */
  readonly changedAtMs: number;
  /** Tombstoned principals never verify and cannot be reactivated by ordinary advancement. */
  readonly status: 'active' | 'tombstoned';
}

PrincipalEpochStore#

Persistent per-principal revocation authority (SPEC §6.6/§10.3).

current() is authoritative and side-effect free. advance() and tombstone() must update one persistent monotone row atomically. Production accepts only a framework-authenticated durable implementation; the memory constructor is deliberately development/test only.

Signature

ts
interface PrincipalEpochStore {
  initialize(principal: string): Promise<PrincipalEpochState> | PrincipalEpochState;
  current(
    principal: string,
    options: PrincipalEpochLookupOptions,
  ): Promise<PrincipalEpochState | undefined> | PrincipalEpochState | undefined;
  advance(
    principal: string,
    reason: PrincipalEpochAdvanceReason,
  ): Promise<PrincipalEpochState> | PrincipalEpochState;
  tombstone(
    principal: string,
    reason: PrincipalEpochTombstoneReason,
  ): Promise<PrincipalEpochState> | PrincipalEpochState;
}

PrincipalEpochTombstoneReason#

Closed reasons that permanently tombstone a principal identity.

Signature

ts
type PrincipalEpochTombstoneReason = 'principal-deletion' | 'provider-deletion';

@kovojs/server/principal-erasure#

Task: Principal erasure orchestration and verifiable receipts.

Source: packages/server/src/public-principal-erasure.ts

Values#

erasePrincipal#

Tombstone one identity, erase all currently enumerable Kovo-owned residue, independently probe every supplied sink, and only then mint a signed point-in-time receipt (SPEC §10.3).

Signature

ts
async function erasePrincipal(
  principal: string,
  options: ErasePrincipalOptions,
): Promise<PrincipalErasureReceipt>;

verifyPrincipalErasureReceipt#

Verify a receipt against the same fixed-purpose key ring without granting generic signing.

Signature

ts
function verifyPrincipalErasureReceipt(
  receipt: PrincipalErasureReceipt,
  signingKeyRing: SigningKeyRing,
): boolean;

Supporting types#

PrincipalErasureIncompleteError#

Fail-closed error raised when any mandatory post-delete absence probe finds residue.

Signature

ts
class PrincipalErasureIncompleteError extends Error {
  readonly sink: 'blobs' | 'durable-tasks' | 'mutation-replay';

  constructor(sink: PrincipalErasureIncompleteError['sink']) {
    super(`Principal erasure absence probe found residue in ${sink}.`);
    this.name = 'PrincipalErasureIncompleteError';
    this.sink = sink;
  }
}

ErasePrincipalOptions#

Runtime and signing authority required to erase one principal from Kovo-owned sinks.

Signature

ts
interface ErasePrincipalOptions {
  /** Exact app runtime whose framework-system task/replay ledgers are covered. */
  readonly runtime: KovoPostgresAppRuntimeDb;
  /** Exact framework key ring used only by the fixed receipt-signing purpose. */
  readonly signingKeyRing: SigningKeyRing;
  /** Every storage adapter wired by this app; omission is outside the receipt's claim. */
  readonly storage: PrincipalErasureStorageSet;
}

PrincipalErasureReceipt#

Exact receipt vocabulary for a point-in-time principal-erasure absence proof.

Signature

ts
interface PrincipalErasureReceipt {
  readonly absenceProbed: true;
  readonly blobObjectsDeleted: number;
  readonly completedAtMs: number;
  readonly durableTaskRowsDeleted: number;
  readonly keyId: string;
  readonly mutationReplayRowsDeleted: number;
  /** One-way principal commitment; the raw principal is never copied into the receipt. */
  readonly principalCommitment: `sha256:${string}`;
  readonly signature: string;
  readonly storageAdaptersProbed: number;
  readonly tombstoneEpoch: number;
  readonly version: 'kovo-principal-erasure-receipt/v1';
}

PrincipalErasureStorageSet#

Complete, non-empty sink set required by {@link erasePrincipal}.

Signature

ts
type PrincipalErasureStorageSet = readonly [StorageCapability, ...StorageCapability[]];

@kovojs/server/render-tree#

Task: Structured component XML parsing and registry-backed tree rendering.

Source: packages/server/src/public-render-tree.ts

Values#

parseComponentXml#

Parse well-formed rich-text XML into a {@link ComponentNode} AST (SPEC §4.10). Handles elements, single/double-quoted and boolean attributes, self-closing tags, text, comments, processing instructions, and CDATA, decoding the standard XML entities. The result is plain data — it is never reconstituted into HTML — so parsing is the trust boundary and can run at write time.

Throws {@link ComponentXmlError} on malformed input (mismatched or unclosed tags, stray markup); v1 assumes the source is well-formed.

Signature

ts
function parseComponentXml(source: string): ComponentNode[];

renderRegistry#

Build a closed component registry for {@link renderTree}. A tag with no entry can never render a component, so the registry IS the pre-approval boundary (SPEC §4.10). Each entry may be a bare Component (attributes pass through as strings) or { component, props } to validate attributes against the component's own s.object({...}) schema.

Copyable example

ts
const registry = renderRegistry({
  'kovo-chart': { component: Chart, props: chartProps },
  'kovo-card': { component: Card, props: cardProps },
});

Signature

ts
function renderRegistry(input: ComponentRegistryInput): ComponentRegistry;

renderTree#

Render registered authored callbacks only in a request-safe bootstrapped realm (SPEC §4.10/§6.6).

Signature

ts
function renderTree(
  registry: ComponentRegistry,
  nodes: ComponentNode | readonly ComponentNode[],
  options: RenderTreeOptions = {},
): Promise<string>;

Supporting types#

ComponentElementNode#

A parsed element node: a tag, its decoded string attributes, and child nodes (SPEC §4.10).

Signature

ts
interface ComponentElementNode {
  type: 'element';
  tag: string;
  attributes: Record<string, string>;
  children: ComponentNode[];
}

ComponentNode#

A node in a parsed rich-text AST (SPEC §4.10).

Signature

ts
type ComponentNode = ComponentElementNode | ComponentTextNode;

ComponentRegistry#

A closed, branded set of pre-approved components produced by {@link renderRegistry} (SPEC §4.10).

Signature

ts
interface ComponentRegistry {
  /** Type-only nominal guard; runtime authority is the module-private render-registry witness. */
  readonly [componentRegistryBrand]: true;
  readonly entries: ReadonlyMap<string, ComponentRegistryEntry>;
}

ComponentRegistryEntry#

One pre-approved registry entry: the component to render plus the s.object({...}) schema that validates the LLM-supplied attributes for this tag (SPEC §4.10, §6.3). Reusing the component's own prop schema keeps validation and rendering in sync. When props is omitted, attributes pass through as strings (still attribute-escaped and URL-scheme-checked at emission by the JSX runtime).

Signature

ts
interface ComponentRegistryEntry {
  component: Component<never>;
  props?: Schema<Record<string, unknown>>;
}

ComponentRegistryInput#

Input accepted by {@link renderRegistry}: tag → component, or tag → { component, props } (SPEC §4.10).

Signature

ts
type ComponentRegistryInput = Record<string, ComponentRegistryEntry | Component<never>>;

ComponentTextNode#

A literal character-data node parsed from rich-text source (SPEC §4.10).

Signature

ts
interface ComponentTextNode {
  type: 'text';
  value: string;
}

RenderTreeOptions#

Behavior for a tag absent from the registry (SPEC §4.10).

Signature

ts
interface RenderTreeOptions {
  /**
   * What to do with an element whose tag has no registry entry. `'text'` (default) renders the
   * element's children and drops the unknown wrapper; `'drop'` omits the element entirely.
   */
  unknownTag?: 'drop' | 'text';
}

ComponentXmlError#

Thrown by {@link parseComponentXml} when the source is not well-formed (SPEC §4.10).

Signature

ts
class ComponentXmlError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'ComponentXmlError';
  }
}

@kovojs/server/rendering#

Task: Advanced route rendering, document authoring, metadata, and prefetch contracts.

Source: packages/server/src/public-rendering.ts

Values#

renderRouteHtml#

Render a custom createApp({ renderRoute }) value through Kovo's framework-owned HTML trust boundary (SPEC §4.5, §9.5). String route-shell HTML remains an explicit app-authored shell result; non-string values are unwrapped only when Kovo minted the rendered/trusted value, otherwise they are escaped as text.

Signature

ts
function renderRouteHtml(value: unknown): string;

Supporting types#

AppDocumentOptions#

Document-level options applied by createApp() when rendering route documents.

Signature

ts
interface AppDocumentOptions {
  /**
   * SPEC §6.6 browser defense-in-depth: compiler-derived CSP origins, reviewed non-static
   * origins, reporting/Trusted Types posture, and optional closed cross-origin isolation.
   * String allowlist origins must match the compiler census; a non-static integration needs
   * the explicit `{ origin, rationale }` escape. Hardening directives remain framework-owned.
   */
  csp?: DocumentCspConfig;
  structured?: DocumentConfig;
  lang?: string;
}

AppErrorShellOptions#

Optional shell renderers for framework-owned error pages in the request shell (SPEC §9.5).

Signature

ts
interface AppErrorShellOptions {
  forbidden?: ErrorShellRenderer;
  notFound?: ErrorShellRenderer;
  serverError?: ErrorShellRenderer;
}

AppRouteRenderContext#

Request-shell context passed to a custom renderRoute hook (SPEC §9.5).

Signature

ts
interface AppRouteRenderContext<
  Route extends { readonly path: string } = {
    readonly path: string;
  },
> {
  params: Record<string, string>;
  request: Request;
  route: Route;
  search: Record<string, string | string[]>;
}

DocumentAuthoringContext#

Request-independent context for structured document declarations (SPEC.md §9.5).

Signature

ts
interface DocumentAuthoringContext {
  readonly environment?: 'build' | 'dev' | 'production' | 'test';
}

DocumentShellAttributes#

Constrained shell attributes collected from HtmlAttrs and BodyAttrs (SPEC.md §9.5).

Signature

ts
type DocumentShellAttributes = Record<string, DocumentShellAttributeValue>;

DocumentShellAttributeValue#

Attribute value accepted by structured document shell attribute primitives.

Signature

ts
type DocumentShellAttributeValue = boolean | number | string | undefined;

I18nCatalog#

A localization message catalog inlined into the document for a locale. Serialized into a kovo-i18n JSON script tag by the page-hint renderer.

Signature

ts
interface I18nCatalog<Messages extends Record<string, string> = Record<string, string>> {
  locale: string;
  messages: Messages;
}

PageHintOptions#

Inputs for rendering a route's document hints: stylesheets and critical CSS (SPEC §13.1), <head> meta, i18n catalogs, module preloads, bootstrap script, and Speculation Rules prefetch/prerender (SPEC §8). Page, mutation-fragment, and deferred-fragment renders share this stylesheet-delivery shape.

Signature

ts
interface PageHintOptions<MetaContext = unknown> {
  bootstrapScript?: string;
  i18n?: I18nCatalog | readonly I18nCatalog[];
  meta?: RouteMetaSource<MetaContext> | readonly RouteMetaSource<MetaContext>[];
  modulepreloads?: readonly string[];
  prefetch?: RoutePrefetch;
  /**
   * Named justification that suppresses KV419 on a guarded `prefetch:'moderate'` route.
   *
   * SPEC §8:756 allows guarded moderate prefetch when the author supplies an explicit
   * rationale (e.g. `"route is idempotent and safe for credentialed prerender"`).
   * A non-empty string silences the diagnostic; an absent or empty string is ignored.
   */
  prefetchJustification?: string;
  prerenderUrls?: readonly string[];
  stylesheets?: readonly (string | StylesheetAsset)[];
}

RouteMetaCallback#

Param/search-aware route metadata callback (SPEC §6.4).

Signature

ts
type RouteMetaCallback<
  Context = unknown,
  Queries extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>,
> = (context: Context, queries: Queries) => RouteMeta;

RouteMetaFactory#

Query-dependent route metadata source: names the queries it reads and resolves those values into a RouteMeta at render time.

Signature

ts
interface RouteMetaFactory {
  queries: readonly string[];
  resolve(values: Record<string, unknown>): RouteMeta;
}

RouteMetaSource#

A route's meta: static, query-driven, or route-context-driven metadata.

Signature

ts
type RouteMetaSource<Context = unknown> =
  | RouteMeta
  | RouteMetaFactory
  | RouteMetaCallback<Context>;

RoutePrefetch#

Per-route Speculation Rules eagerness (SPEC §8). 'conservative' and 'moderate' opt into prefetch/prerender; false (the default) emits nothing. 'moderate' is compile-gated on guarded/session-dependent routes (KV419).

Signature

ts
type RoutePrefetch = 'conservative' | 'moderate' | false;

RegionPriority#

Priority for a server-rendered region inside the initial route document (SPEC §8).

Signature

ts
type RegionPriority = 'after-paint' | 'critical' | 'visible';

ServerFragmentRenderable#

HTML-capable value accepted by app-facing fragment APIs. Plain strings belong in text sinks.

Signature

ts
type ServerFragmentRenderable = ServerRenderedHtml | TrustedHtml;

ServerRenderedHtml#

Framework-rendered HTML object accepted by fragment sinks without naming internal brands.

Signature

ts
interface ServerRenderedHtml {
  readonly html: string;
  toJSON?(): string;
  toString(): string;
}

@kovojs/server/replay#

Task: Mutation replay stores and Postgres replay surfaces.

Source: packages/server/src/public-replay.ts

Values#

createMemoryMutationReplayStore#

Build the default in-memory {@link MutationReplayStore} (SPEC §9.1/§10.3): admitted replay keys are bounded by maxEntries; canonical committed truth is reclaimed only at its token expiry, while pending claims and unparseable legacy truth are never time-evicted. Unseen work is refused at capacity so callers fail closed before running the handler.

Signature

ts
function createMemoryMutationReplayStore<
  Response extends MutationReplayResponse = MutationReplayResponse,
>(options: MutationReplayStoreOptions = {}): MutationReplayStore<Response>;

replayMutationWireBody#

Rehydrate a persisted mutation replay body through an explicit audited escape path.

Normal query/mutation responses are minted by framework renderers. Apps that implement a durable MutationReplayStore may need to deserialize a previously stored framework response; this constructor keeps that escape visible and reason-bearing instead of allowing plain strings to satisfy the mutation wire body type.

Signature

ts
function replayMutationWireBody(
  body: string,
  options: ReplayMutationWireBodyOptions,
): MutationReplayBody;

Supporting types#

MutationReplayReservation#

A pending reservation returned by {@link MutationReplayStore.reserve}: commit the eventual response or abort to release the slot (SPEC §9.1). Part of the public replay-store surface (recursive publicness, rules/api-surface.md).

Signature

ts
interface MutationReplayReservation<
  Response extends MutationReplayResponse = MutationReplayResponse,
> {
  /**
   * Abandon the reservation without committing a result, releasing the pending
   * record so a corrected retry can run (e.g. after a non-replayable validation
   * failure). Optional for backward compatibility with stores predating
   * security finding M4; callers must tolerate its absence.
   */
  abort?(): Promise<void> | void;
  commit(response: Response): Promise<void> | void;
}

MutationReplayResponse#

Persistable framework mutation response accepted by a SPEC §10.3 replay store.

Signature

ts
type MutationReplayResponse = ServerResponseBase<
  MutationReplayBody,
  ResponseHeaders,
  200 | 303 | 401 | 403 | 409 | 422 | 429 | 500
>;

MutationReplayStore#

Idempotent mutation/webhook replay store contract (SPEC §9.1): look up a prior response by the runtime-witnessed key, reserve a pending slot for an in-flight handler, and record the committed response. scope and idem remain descriptive/token metadata only; the complete canonical ScopedKey frame is the namespace authority. Apps may inject a custom store for local development and tests; deployed mutation declarations require the framework-authenticated durable store returned by createPostgresAppRuntimeDb().mutationReplayStore. The framework provides {@link createMemoryMutationReplayStore} as the default in-memory development implementation.

Signature

ts
interface MutationReplayStore<
  Response extends MutationReplayResponse = MutationReplayResponse,
> {
  get(
    key: ScopedKey,
    scope: string,
    idem: string,
    fingerprint?: string,
    principal?: string,
  ): Promise<Response | undefined> | Response | undefined;
  reserve(
    key: ScopedKey,
    scope: string,
    idem: string,
    fingerprint?: string,
    principal?: string,
  ):
    | MutationReplayReservation<Response>
    | Promise<MutationReplayReservation<Response> | undefined>
    | undefined;
  set(
    key: ScopedKey,
    scope: string,
    idem: string,
    response: Response,
    fingerprint?: string,
    principal?: string,
  ): Promise<void> | void;
}

MutationReplayStoreOptions#

Capacity posture for the development/test-only in-memory mutation replay store.

Signature

ts
interface MutationReplayStoreOptions {
  /** Maximum total number of retained pending or committed replay keys. */
  maxEntries?: number;
  /**
   * E4 (SPEC §9.1:1073 atomic reservation; §9.5:914 pre-dispatch shed): a separate
   * bound on concurrent *in-flight pending* reservations, independent of `maxEntries`.
   * Part-2 A6 (SPEC §10.3:1063/1065) correctly stopped EVICTING pending slots to avoid
   * the M4 double-execute hazard, but that left pending reservations free to bypass
   * `maxEntries`; M7 additionally requires them to remain joined without TTL eviction until
   * explicit commit/abort. An authenticated attacker firing many
   * concurrent slow mutations with client-chosen `Kovo-Idem` values could accumulate
   * unbounded pending records. When the number of pending reservations is at this cap,
   * `reserve()` REFUSES a new reservation (callers fail closed) rather than EVICTING an
   * existing pending slot (which would re-open A6/M4).
   * Defaults to `maxEntries`; the total `maxEntries` admission bound always applies first.
   */
  maxPending?: number;
  /**
   * @deprecated Accepted as a validated legacy retention hint but intentionally ignored. Canonical
   * mutation tokens carry their normative expiry; unparseable legacy keys remain retained.
   */
  ttlMs?: number;
}

ReplayMutationWireBodyOptions#

Options for rehydrating a persisted framework mutation replay body.

Signature

ts
interface ReplayMutationWireBodyOptions {
  /** Audit-readable reason this stored body is being reintroduced to the framework wire. */
  reason: string;
}

MutationReplayBody#

Audited, framework-compatible body accepted by a custom mutation replay store.

Construct persisted strings with {@link replayMutationWireBody}; the private brand is an author-time guardrail while replay decoding and response sinks retain runtime enforcement.

Signature

ts
type MutationReplayBody = string & {
  readonly [frameworkWireBodyBrand]: true;
};

PostgresPendingReplayReleaseOptions#

Audit-readable manual release posture for a confirmed crash-orphaned pending claim.

Signature

ts
interface PostgresPendingReplayReleaseOptions {
  justification: string;
}

PostgresPendingReplayTarget#

Explicit target for operator reconciliation of a crash-orphaned pending replay claim.

Signature

ts
interface PostgresPendingReplayTarget {
  generation: string;
  idem: string;
  scope: string;
  surface: Exclude<PostgresReplaySurface, 'capability'>;
}

PostgresReplaySurface#

Durable replay namespace; capability, mutation, and webhook keys cannot collide.

Signature

ts
type PostgresReplaySurface = 'capability' | 'mutation' | 'webhook';

@kovojs/server/routing#

Task: Advanced endpoint, guard, route, and response declaration types.

Source: packages/server/src/public-routing.ts

Supporting types#

AppRateLimitOptions#

Coarse request-rate budget enforced by the request shell before dispatch (SPEC §9.5).

Signature

ts
interface AppRateLimitOptions {
  /** Maximum accepted requests within `windowMs` (1..1,000,000). */
  max: number;
  /** Maximum distinct keys retained for this budget (1..100,000). */
  maxKeys?: number;
  /** Sliding bucket duration in milliseconds (1..86,400,000). */
  windowMs?: number;
}

AppRequestLimitOptions#

Request-shell load-shedding configuration. Defaults are filled in by createApp() so every app has a printable/enforceable posture (SPEC §9.5).

Signature

ts
interface AppRequestLimitOptions extends AppRequestRateLimitOptions {
  /**
   * End-to-end request deadline in milliseconds. The framework aborts owned effects and discards
   * a response that has not crossed the response mint door in time. Must be 1..300,000; arbitrary
   * synchronous JavaScript remains cooperatively, not forcibly, cancellable (SPEC §9.5).
   */
  deadlineMs?: number;
  /**
   * Maximum accepted request body size. The shell rejects an oversized `Content-Length`
   * before dispatch and wraps body readers so chunked/missing-length bodies fail with 413
   * before parse. Must be between 0 and 67,108,864 bytes; the gate cannot be disabled.
   */
  maxBodyBytes?: number;
  /** Maximum concurrently admitted requests for this app instance (1..10,000; SPEC §9.5). */
  maxInFlight?: number;
  /**
   * Maximum array length a framework-owned query/list result may ship to the client wire.
   * Defaults to the API4 resource-consumption floor; an audited large-read surface may raise it
   * up to 100,000 (SPEC §9.5).
   */
  maxQueryListItems?: number;
  /**
   * Optional app-owned opaque key extractor used by the coarse per-IP limiter. Its result is
   * bounded but is not reinterpreted as a built-in proxy IP literal (SPEC §9.5).
   */
  clientIp?: (request: Request) => string | undefined;
  /**
   * Trust canonical address-only client IPs from the built-in forwarded-header classifier.
   * Exactly one of X-Forwarded-For, X-Real-IP, or Forwarded may be present; a multi-family ingress
   * is ambiguous and falls back to adapter peer/global identity. Disabled by default;
   * adapter/operator-owned proxy boundaries must opt in (SPEC §9.5).
   */
  trustedProxy?: boolean;
  /** Additional budgets applied to `/_m/<mutation>` requests. */
  mutations?: AppRequestRateLimitOptions;
  /** Additional budgets applied to `/_q/<query>` requests. */
  queries?: AppRequestRateLimitOptions;
}

AppRequestRateLimitOptions#

Per-surface request-rate budgets enforced before dispatch (SPEC §9.5).

Signature

ts
interface AppRequestRateLimitOptions {
  global?: AppRateLimitOptions;
  perIp?: AppRateLimitOptions;
}

Endpoint#

A raw HTTP endpoint descriptor: path, method, mount mode, and auth/CSRF declarations.

Signature

ts
interface Endpoint<
  Path extends string,
  Method extends EndpointMethod = EndpointMethod,
  Mount extends EndpointMount = 'exact',
> {
  access?: AccessDecision;
  auth?: EndpointAuthDeclaration;
  csrf?: EndpointCsrfExemption;
  method: Method;
  mount: Mount;
  mountJustification?: string;
  path: Path;
  reason: string;
  response: EndpointResponsePosture;
}

EndpointAuthDeclaration#

How an endpoint authenticates: a named verifier, a named custom scheme, or a justified none.

Signature

ts
type EndpointAuthDeclaration =
  | { kind: 'custom'; name: string; verify?: WebhookVerifier }
  | { kind: 'none'; justification: string }
  | { kind: 'verifier'; name: string; verify?: WebhookVerifier };

EndpointCachePosture#

Raw endpoint cache posture declared for endpoint audit output (SPEC §9.1).

Signature

ts
type EndpointCachePosture = 'custom' | 'no-store' | 'private' | 'public' | 'revalidated';

EndpointCsrfExemption#

Records an explicit, justified opt-out of default-on CSRF for an unsafe endpoint (SPEC §6.6).

Signature

ts
interface EndpointCsrfExemption {
  exempt: true;
  justification: string;
}

EndpointDbContext#

Context exposed only to endpoint(..., { db: true, handler(req, ctx) { ... } }).

Signature

ts
interface EndpointDbContext<
  Db = unknown,
  Method extends EndpointMethod = EndpointSafeMethod,
> {
  /**
   * SPEC §10.3 DEC-H: endpoints do not inherit a session principal. App code must derive and
   * validate the owner id from its own endpoint auth before receiving managed DB capabilities.
   */
  actAs(principalId: string): Promise<EndpointDbScope<Db, Method>>;
}

EndpointDbDefinitionBase#

Endpoint definition branch for handlers that opt into ctx.actAs(id) managed DB access.

Signature

ts
interface EndpointDbDefinitionBase<Method extends EndpointMethod, Db = unknown> {
  access?: AccessDecision;
  auth?: EndpointAuthDeclaration;
  db: true;
  handler: EndpointDbHandler<Db, Method>;
  method: Method;
  response: EndpointResponsePosture;
}

EndpointDbHandler#

An endpoint handler that opted into an explicit principal-scoped DB context.

Signature

ts
type EndpointDbHandler<Db = unknown, Method extends EndpointMethod = EndpointSafeMethod> = (
  request: EndpointRequest,
  context: EndpointDbContext<Db, Method>,
) => Promise<Response> | Response;

EndpointDbScope#

Principal-scoped endpoint DB capabilities. Safe methods receive only read; a statically known unsafe method receives write too. The runtime independently enforces the same split (SPEC §9.1), so this conditional type is defense-in-depth rather than the security proof.

Signature

ts
type EndpointDbScope<Db = unknown, Method extends EndpointMethod = EndpointSafeMethod> = {
  readonly db: {
    readonly read: Reader<Db>;
  } & (string extends Method
    ? object
    : Uppercase<Method> extends EndpointSafeMethod
      ? object
      : { readonly write: Writer<Db> });
};

EndpointDeclaration#

An endpoint with its path attached, as returned by endpoint().

Signature

ts
interface EndpointDeclaration<
  Path extends string = string,
  Method extends EndpointMethod = EndpointMethod,
  Mount extends EndpointMount = EndpointMount,
  Db = unknown,
> extends Endpoint<Path, Method, Mount> {
  db?: true;
  handler: EndpointHandler | EndpointDbHandler<Db, EndpointMethod>;
}

EndpointHandler#

An endpoint handler: maps a session-free Request to a Response.

Signature

ts
type EndpointHandler = (request: EndpointRequest) => Promise<Response> | Response;

EndpointLongLivedResponsePosture#

A bounded audited extension for one endpoint that intentionally outlives the app default.

Signature

ts
interface EndpointLongLivedResponsePosture {
  /** Finite end-to-end deadline for this endpoint (1..300,000 milliseconds; SPEC §9.5). */
  deadlineMs: number;
  /** Why this streaming or long-poll endpoint needs a wider request lifetime. */
  justification: string;
}

EndpointMount#

Whether an endpoint matches an exact path or a path prefix.

Signature

ts
type EndpointMount = 'exact' | 'prefix';

EndpointMountDefinition#

Prefix endpoint mounts must justify the wider routed surface (SPEC §9.1).

Signature

ts
type EndpointMountDefinition<Mount extends EndpointMount> = Mount extends 'prefix'
  ? { mount: Mount; mountJustification: string }
  : { mount?: Mount; mountJustification?: never };

EndpointResponseBody#

Raw response body posture declared for endpoint audit output (SPEC §9.1).

Signature

ts
type EndpointResponseBody = 'bytes' | 'html' | 'json' | 'redirect' | 'stream' | 'text';

EndpointResponseBodyPosture#

One or more raw response body classes an endpoint may return, used by endpoint audits and runtime posture verification (SPEC §9.1).

Signature

ts
type EndpointResponseBodyPosture =
  | EndpointResponseBody
  | readonly [EndpointResponseBody, ...EndpointResponseBody[]];

EndpointSafeMethod#

Closed safe-method set whose framework-owned endpoint capabilities are read-only (SPEC §9.1).

Signature

ts
type EndpointSafeMethod = 'GET' | 'HEAD' | 'OPTIONS';

AuthenticatedRequest#

A request narrowed to one with a present session user, produced by guards.authed.

Signature

ts
type AuthenticatedRequest<Request extends SessionRequestLike> = Request & {
  session: NonNullable<Request['session']> & {
    user: NonNullable<NonNullable<Request['session']>['user']>;
  };
};

ClientIpRequestLike#

A request carrying the framework-resolved, trustworthy client IP that guards.rateLimit({ per: 'ip' }) keys on (SPEC §9.5). The request shell attaches req.clientIp (via resolveLifecycleRequest's clientIp resolver) from the SAME trusted source the coarse pre-dispatch load-shed limiter uses — the app-configured createApp({ requestLimits: { clientIp } }) extractor, else X-Forwarded-For/X-Real-IP/Forwarded ONLY when trustedProxy is set (app-load-shed.ts resolveRequestClientIp). The guard never reads a raw client-supplied header itself, so a spoofed X-Forwarded-For cannot pick the rate-limit bucket on an untrusted edge.

Signature

ts
interface ClientIpRequestLike {
  /** Framework-resolved client IP attached by the request shell before the guard chain (SPEC §9.5). */
  clientIp?: string;
}

ForbiddenContext#

Context passed to a renderForbidden renderer when an authenticated-but-unauthorized guard refinement fails (SPEC §6.5). Carries the failing request.

Signature

ts
interface ForbiddenContext<Request> {
  request: Request;
}

ForbiddenDenial#

The caller is authenticated but not permitted. SPEC §6.5: the framework renders the app's 403 shell with status 403.

Signature

ts
interface ForbiddenDenial {
  kind: 'forbidden';
  payload?: Record<string, unknown>;
}

ForbiddenRenderer#

App-supplied renderer for the 403 forbidden shell on authorization failure (SPEC §6.5). Returns the HTML body served with status 403. Used to type the renderForbidden request-shell option.

Signature

ts
type ForbiddenRenderer<Request> = (
  context: ForbiddenContext<Request>,
) => string | Promise<string>;

GuardArgsRequest#

A guard request carrying the query's/mutation's framework-merged validated args an arg-aware guard inspects (SPEC §10.3:1155-1157 "Guards (arg-aware, normative)", §9.4). The query/mutation runners thread the same s.*-coerced args the loader/handler see onto the request after schema parse/coerce and before the guard chain, so an ownership guard's keyOf can read req.args without a cast. Pass it as the keyed request view while the guard remains base-typed, e.g. guards.owns<AppRequest, GuardArgsRequest<AppRequest, { id: string }>, string>(...).

Signature

ts
type GuardArgsRequest<Request, Args = unknown> = Request & { args: Args };

GuardDenial#

A guard denial that expresses the user-facing intent of a rejection, leaving the HTTP status to the framework. SPEC §6.5 fixes the three outcomes: an unauthenticated caller is sent through the app's onUnauthenticated handler (default: a 303 redirect to the login route with the original URL as next); an authenticated-but-unauthorized caller renders the app's 403 shell; a rate-limited caller gets a 429 carrying retryAfter seconds. The wire status is derived from kind inside the framework (renderHttpGuardFailureResponse), so an author reads the intent, not a transport detail. Return true to allow.

Signature

ts
type GuardDenial = UnauthenticatedDenial | ForbiddenDenial | RateLimitedDenial;

GuardParamsRequest#

A guard request carrying the framework-merged resolved route params an arg-aware route guard inspects (SPEC §10.3:1155-1157, §6.4). runRoutePage threads the route's parsed/coerced params onto the request before the layout/route guard chain, so an ownership guard's keyOf can read req.params without a cast and discharge KV414 for a route-instance key.

Signature

ts
type GuardParamsRequest<Request, Params = Record<string, string>> = Request & {
  params: Params;
};

GuardResult#

What a guard returns: true to allow, or a {@link GuardDenial} to reject (SPEC §6.5).

Signature

ts
type GuardResult = boolean | GuardDenial;

RateLimitedDenial#

The caller exceeded a rate limit. SPEC §6.5: the framework answers 429 and surfaces retryAfter (seconds) as a Retry-After header.

Signature

ts
interface RateLimitedDenial {
  kind: 'rateLimited';
  payload?: Record<string, unknown>;
  retryAfter?: number;
}

RateLimitOptions#

Options for guards.rateLimit: window size, max requests, scope, and key function (SPEC §9.5/§10.3). The per dimension keys the per-principal budget: 'session' (default) keys by session id, 'global' collapses all callers into one bucket, and 'ip' keys by the framework-resolved client IP (req.clientIp, see {@link ClientIpRequestLike}) so an anonymous / per-IP budget can be expressed at the guard layer (SPEC §9.5:935). This per-principal guard combinator composes with — does not replace — the coarse pre-dispatch per-IP/global load-shed limiter (SPEC §9.5; app-load-shed.ts).

Signature

ts
interface RateLimitOptions<Request> {
  key?: (request: Request) => string;
  max: number;
  maxKeys?: number;
  per?: 'global' | 'session' | 'ip';
  windowMs?: number;
}

SessionDefinition#

The app's session declaration returned by session(): parse, provider, and schema.

Signature

ts
interface SessionDefinition<Value> {
  parse(request: { session?: unknown }): Value;
  provider<RawRequest>(
    provider: SessionProvider<RawRequest, Value>,
  ): SessionProvider<RawRequest, Value>;
  schema: Schema<Value>;
}

SessionProviderResult#

The result a {@link SessionProvider} resolves to. Backward-compatibly, a provider may return a plain SessionValue (or null/undefined). part-3 I2 (SPEC §6.5, §9.1.1:854): a provider backed by a rolling/refresh session (e.g. Better Auth updateAge or cookieCache) may instead return { value, setCookies } so the framework forwards the provider's fresh Set-Cookie headers onto the resolved GET response — otherwise a continuously-active user is silently hard-logged-out at the original session boundary. The plain-value form remains fully supported; this is purely additive.

Signature

ts
interface SessionProviderResult<SessionValue> {
  /** Raw `Set-Cookie` header strings the provider wants forwarded on the response. */
  setCookies?: readonly string[];
  value: SessionValue | null | undefined;
}

SessionRequestLike#

A request carrying an optional session; the constraint for built-in guards.

Signature

ts
interface SessionRequestLike {
  session?: {
    id?: string;
    user?: SessionUserLike | null;
  } | null;
}

SessionUserLike#

The minimal authenticated-user shape guards inspect: id and roles.

Signature

ts
interface SessionUserLike {
  id?: string;
  roles?: readonly string[];
}

UnauthenticatedContext#

Context passed to an onUnauthenticated handler when an authed guard fails (SPEC §6.5). next is the framework-validated same-origin path to return to after login; request is the failing request.

Signature

ts
interface UnauthenticatedContext<Request> {
  next: string;
  request: Request;
}

UnauthenticatedDenial#

The caller is not authenticated. SPEC §6.5: the framework runs the app's onUnauthenticated handler, whose default is a 303 redirect to the login route with the original URL available as next.

Signature

ts
interface UnauthenticatedDenial {
  kind: 'unauthenticated';
  payload?: Record<string, unknown>;
}

UnauthenticatedHandler#

App-supplied handler for unauthenticated guard failures (SPEC §6.5). Returns the CoreRedirect to the login route; the default is a 303 to the configured login path carrying next. Used to type the onUnauthenticated request-shell option.

Signature

ts
type UnauthenticatedHandler<Request> = (
  context: UnauthenticatedContext<Request>,
) => CoreRedirect | Promise<CoreRedirect>;

LayoutDeclaration#

A first-class page-chrome segment, as returned by layout().

Signature

ts
interface LayoutDeclaration<
  Request = unknown,
  Queries extends Readonly<Record<string, QueryDefinition<string, any, any, Request>>> = Readonly<
    Record<string, QueryDefinition<string, any, any, Request>>
  >,
  Page extends LayoutRenderResult = LayoutRenderResult,
  Regions extends LayoutRegionResults = LayoutRegionResults,
> extends LayoutDefinition<Request, Queries, Page, Regions> {}

LayoutFactory#

App-scoped layout factory whose guards and render slots see the configured request shape.

Signature

ts
interface LayoutFactory<Request = unknown> {
  <
    const Queries extends Readonly<Record<string, QueryDefinition<string, any, any, Request>>> =
      Readonly<Record<string, QueryDefinition<string, any, any, Request>>>,
    Page extends LayoutRenderResult = LayoutRenderResult,
    Regions extends LayoutRegionResults = LayoutRegionResults,
  >(
    definition: Omit<LayoutDefinition<Request, Queries, Page, Regions>, 'access' | 'guard'> &
      (
        | { access: AccessDecision; guard?: never }
        | { access?: never; guard: Guard<Request> }
        | { access?: never; guard?: never }
      ),
  ): LayoutDeclaration<Request, Queries, Page, Regions>;
}

LayoutQueryResults#

Resolved layout query values passed to a layout().render function (SPEC §4.5/§9.5).

Signature

ts
type LayoutQueryResults<Queries> = {
  [Name in keyof Queries]: Queries[Name] extends QueryDefinition<string, infer Value, any, any>
    ? Awaited<Value>
    : unknown;
};

LayoutRegionResults#

Region values passed to layout render slots when no narrower route contract is declared.

Signature

ts
type LayoutRegionResults = Readonly<Record<never, never>>;

LayoutRenderResult#

Non-string chrome value accepted from public layout().render callbacks (SPEC §4.1, §9.5).

Signature

ts
type LayoutRenderResult = RoutePageResult;

RouteBoundaries#

Per-segment boundaries that override app-level error shells for matching route failures.

Signature

ts
interface RouteBoundaries<
  Request = unknown,
  Page extends RoutePageResult = RoutePageResult,
> {
  error?: RouteBoundaryRenderer<Request, Page>;
  notFound?: RouteBoundaryRenderer<Request, Page>;
  unauthorized?: RouteBoundaryRenderer<Request, Page>;
}

RouteBoundaryContext#

Context passed to route/layout segment boundary renderers.

Signature

ts
interface RouteBoundaryContext<Request> {
  error?: unknown;
  request: Request;
  status: 403 | 404 | 500;
}

RouteBoundaryRenderer#

Render a route/layout segment boundary for expected route failures or errors.

Signature

ts
type RouteBoundaryRenderer<Request, Page extends RoutePageResult = RoutePageResult> = (
  context: RouteBoundaryContext<Request>,
) => Page | Promise<Page>;

RouteDeclaration#

A RouteDefinition with its path attached, as returned by route().

Signature

ts
interface RouteDeclaration<
  Path extends string,
  ParamsSchema extends Schema<Record<string, string>> | undefined = undefined,
  SearchSchema extends Schema<Record<string, RouteSearchValue>> | undefined = undefined,
  Request = unknown,
  Page extends RoutePageResult = RoutePageResult,
  GuardedRequest extends Request = Request,
> extends RouteDefinition<Path, ParamsSchema, SearchSchema, Request, Page, GuardedRequest, any> {
  path: Path;
}

RouteRegionDefinitions#

Public route-level sibling region declarations for layout composition (SPEC §4.5/§8).

Signature

ts
type RouteRegionDefinitions<
  Context = unknown,
  Request = unknown,
  Page extends RoutePageResult = RoutePageResult,
> = Readonly<Record<string, (context: Context, request: Request) => Page | Promise<Page>>>;

RouteRegionResults#

Resolved route-region values passed to a layout from a route's regions declarations.

Signature

ts
type RouteRegionResults<Regions> =
  Regions extends RouteRegionDefinitions<any, any, any>
    ? Readonly<{
        [Name in keyof Regions]: Regions[Name] extends (...args: any[]) => infer Value
          ? Awaited<Value>
          : unknown;
      }>
    : LayoutRegionResults;

RouteRequestInput#

Raw, unparsed params/search input handed to a route before schema parsing.

Signature

ts
interface RouteRequestInput {
  params?: unknown;
  search?: unknown;
  /**
   * The `ctx.signUrl` capability the dispatcher threads onto the route context (SPEC §6.6 / §9.1).
   * Built from the framework signing secret via `createSignUrl`; omitted when no secret is configured.
   */
  signUrl?: SignUrlContext['signUrl'];
}

NotFound#

The 404 marker returned by notFound().

Signature

ts
interface NotFound {
  notFound: true;
  status: 404;
}

RedirectLocationAllowlistEntry#

An explicit, audit-readable cross-origin redirect target allowance.

Signature

ts
interface RedirectLocationAllowlistEntry {
  /** Exact origin, e.g. `https://accounts.example.com`. */
  origin: string;
  /** Human-readable reason the app may navigate users to this origin. */
  reason: string;
}

RouteFileOptions#

Options for respond.file: content type and optional filename/etag/headers.

Signature

ts
interface RouteFileOptions<Headers extends Record<string, string> = Record<string, string>> {
  contentType: string;
  etag?: string;
  filename?: string;
  headers?: Headers & {
    [Name in keyof Headers]: Name extends string
      ? string extends Name
        ? Headers[Name]
        : Lowercase<Name> extends Lowercase<AppResponseHeaderName>
          ? Headers[Name]
          : never
      : Headers[Name];
  };
}

RoutePageResponse#

A fully rendered route HTTP response (status, headers, body). Headers use {@link ResponseHeaders} so the document path can carry multiple Set-Cookie values (e.g. a rolling-session refresh + cookie-cache cookie, part-3 I2), matching the mutation response channel.

Signature

ts
interface RoutePageResponse extends ServerResponseBase<
  RouteResponseBody,
  ResponseHeaders,
  RouteResponseStatus
> {
  /** internal The request after the route lifecycle resolved session/db (SPEC §6.5). */
  lifecycleRequest?: unknown;
}

RouteResponseStatus#

HTTP statuses Kovo route page responses may emit after route lifecycle resolution.

Signature

ts
type RouteResponseStatus = 200 | 303 | 304 | 403 | 404 | 422 | 429 | 500;

RouteStoredFileOptions#

Options for respond.storedFile: optional download filename and inline/attachment disposition. The content type is always the SERVER-SNIFFED type of the stored bytes (KV428), never supplied by the caller.

Signature

ts
interface RouteStoredFileOptions {
  disposition?: 'attachment' | 'inline';
  filename?: string;
}

RouteStreamOptions#

Options for respond.stream: RouteFileOptions plus inline/attachment disposition.

Signature

ts
interface RouteStreamOptions<
  Headers extends Record<string, string> = Record<string, string>,
> extends RouteFileOptions<Headers> {
  disposition?: 'attachment' | 'inline';
  /**
   * KV428 inline opt-in (SPEC §6.6/§9.1): set ONLY when the body bytes have been proven safe to
   * render inline — the framework re-encoded/rasterized them, or they came through a deep-sniff
   * `inlineSafe` pass. Required for `disposition: 'inline'` on an un-bufferable stream body; for an
   * in-memory body (string/bytes/ArrayBuffer) the runtime deep-sniffs instead and this brand is the
   * explicit override of that check. Setting it on attacker-controlled active content (HTML/SVG) is
   * the audited risk the brand records.
   */
  unsafeInline?: UnsafeInlineAcceptance;
}

ServerResponseBase#

The common shape of every server response: body, headers, and status.

Signature

ts
interface ServerResponseBase<
  Body,
  Headers extends ResponseHeaders = ResponseHeaders,
  Status extends number = number,
> {
  body: Body;
  headers: Headers;
  status: Status;
}

@kovojs/server/runtime-bootstrap#

Task: First-import runtime lockdown for custom server entries.

Source: packages/server/src/runtime-bootstrap.ts

No public exports are declared by this subpath.

@kovojs/server/secret-reading#

Task: Explicit secret-read capability declarations.

Source: packages/server/src/public-secret-reading.ts

Values#

declareSecretReadCapability#

Attach an audited raw secret-read declaration to a statement object.

Raw SQL that references a secret table is refused unless it carries this declaration; the resulting rows are still boxed before egress (SPEC §10.3/§11.2).

Signature

ts
function declareSecretReadCapability<T extends object>(
  statement: T,
  declaration: DeclaredSecretReadCapability,
): T;

Supporting types#

DeclaredSecretReadCapability#

Audited declaration allowing a raw SQL statement to read secret columns.

Signature

ts
interface DeclaredSecretReadCapability {
  /** Secret physical column names the raw statement is expected to read. */
  columns: readonly string[];
  /** Reviewable reason for using raw SQL to read secret material. */
  justification: string;
  /** Human-readable source label for audit/debugging. */
  source: string;
  /** Physical secret table name. */
  table: string;
}

@kovojs/server/security#

Task: Explicit security postures for cookies, CSRF, uploads, CSP, and regular expressions.

Source: packages/server/src/public-security.ts

Values#

accept#

The verified-MIME / unverified-escape acceptance namespace passed to s.file().accept(...).

  • accept([...types]) — the bytes are sniffed and the sniffed type must be one of types (server truth must agree with the app's allowlist). By-construction-ish.
  • accept.unverified([...types], justification) — the audited escape: trust the client MIME, recorded for kovo explain capabilities. Still attachment-forced.

Signature

ts
function accept(types: readonly string[]): readonly string[];

unsafeCookie#

Construct the audited unsafe escape for an intentional insecure cookie downgrade (SPEC §6.6/§9.1). Without this escape, downgrading a session/auth-class cookie's floor (HttpOnly/Secure false, or SameSite=None) is rejected with KV432. With it, the downgrade is allowed and recorded for kovo explain cookies.

Copyable example

ts
import { unsafeCookie, type CookieOptions } from '@kovojs/server/security';

const embeddedSessionCookie: CookieOptions = {
  class: 'session',
  sameSite: 'none',
  unsafe: unsafeCookie({ downgrade: { sameSite: 'none' }, justification: 'third-party embed' }),
};

Signature

ts
function unsafeCookie(downgrade: UnsafeCookieDowngradeInput): UnsafeCookieDowngrade;

mintCsrfField#

Render a CSRF hidden field for a response that can set the anonymous binding cookie.

This low-level helper backs verified raw endpoint bootstraps. Include html in the raw endpoint protocol; a verified endpoint dispatched by createRequestHandler() captures and delivers setCookie during final response reconstruction. Manually attaching it is app-authored browser state and requires the same endpoint proof. A detached/direct first mint fails closed. The endpoint POST can then keep default CSRF enabled instead of using csrf: false.

Signature

ts
function mintCsrfField<Request>(
  request: Request,
  options: CsrfOptions<Request> & {
    audience?: string;
    field?: string;
    mutation?: string | { readonly key: string };
  },
): MintedCsrfField;

mintCsrfToken#

Mint a CSRF token for a response that can also set the anonymous binding cookie (SPEC §6.6/§9.1).

Use this for first anonymous route responses or verified raw endpoint bootstraps. Session-bound requests return only a token. Anonymous requests mint the framework-owned anonymous CSRF cookie and return its exact bytes in setCookie; createRequestHandler() also captures those bytes and attaches them while reconstructing an authorized response. An explicit raw Set-Cookie remains app-authored browser state and requires the endpoint's executable/private auth proof. A first mint must run during framework-managed response construction; detached and direct runEndpoint() calls have no managed delivery sink and fail closed.

Signature

ts
function mintCsrfToken<Request>(
  request: Request,
  options: CsrfOptions<Request>,
  context: { audience?: string; mutation?: string | { readonly key: string } } = {},
): MintedCsrfToken;

unsafeRegex#

The audited escape (SPEC §6.6/§9.5): accept the ReDoS risk of an arbitrary RegExp explicitly. Records a capability fact surfaced in kovo explain capabilities so a reviewer sees every place a potentially-catastrophic pattern is trusted. Use only when a blessed format and a linear-safe pattern() literal cannot express the need.

Parameter Type Description
regex RegExp The (potentially unsafe) regular expression.
justification string Why the ReDoS risk is acceptable here (required, audited).

Signature

ts
function unsafeRegex(regex: RegExp, justification: string): UnsafeRegexBrand;

Supporting types#

InlineUnverifiedUploadError#

Thrown at the respond.* inline sink when an upload is served inline (disposition: 'inline') but the content type is NOT verified-safe (KV428, SPEC §6.6/§9.1). This is the runtime fail-closed floor: when the static brand degrades (e.g. the stored-file response sink takes a bare string key with no compile-visible verification), the runtime refuses to serve unverified bytes inline rather than rendering attacker-controlled active content same-origin.

Signature

ts
class InlineUnverifiedUploadError extends Error {
  readonly code: 'KV428';

  constructor(message: string) {
    const diagnostic = createRegisteredDiagnostic('KV428', {}, { message });
    super(`${diagnostic.code} ${diagnostic.message}`);
    this.code = diagnostic.code;
    this.name = 'InlineUnverifiedUploadError';
  }
}

UnverifiedAcceptance#

The audited escape (SPEC §6.6/§9.1): opt OUT of byte-sniffing and trust the client-declared MIME. This is the ONLY verbatim-client-MIME path that survives the .mime() removal. It records a capability fact surfaced in kovo explain capabilities so a reviewer sees every place the server trusts the client's content-type claim.

The unverified type is STILL forced to attachment (it is by definition not inline-safe); the escape only changes the download type, never re-enables inline rendering of unverified bytes.

Signature

ts
interface UnverifiedAcceptance {
  readonly [unverifiedAcceptanceBrand]: { readonly kind: 'unverified-upload-acceptance' };
  readonly justification: string;
  readonly types: readonly string[];
  readonly unverified: true;
}

CookieClass#

The security class of a cookie, which selects the by-construction attribute floor applied at the single serializeCookie sink (SPEC §6.6/§9.1, secure-framework Phase 5). The floor exists so an insecure cookie cannot be expressed by default.

  • session / auth — credential-bearing cookies (session id, auth token, CSRF binding). They get a forced floor: HttpOnly (defends against XSS theft), Secure in production (defends against MITM), and an explicit SameSite (defends against CSRF). A __Host-/__Secure- name prefix is applied where the attributes satisfy the browser-enforced prefix contract.
  • app-data — non-credential application cookies (theme, locale). No HttpOnly/Secure floor is forced (these are frequently read by client JS by design), but an explicit SameSite is still defaulted so the cookie is never silently CSRF-exposed.

Signature

ts
type CookieClass = 'app-data' | 'auth' | 'session';

CookieOptions#

Attribute options for a typed Set-Cookie header, accepted by the third argument of MutationContext.setCookie (SPEC §6.6 / §9.1.1). Values are serialized and validated by serializeCookie; control characters and semicolons are rejected.

Signature

ts
interface CookieOptions {
  /**
   * The security class that selects the attribute floor (SPEC §6.6/§9.1). When omitted, Kovo applies
   * the **credential floor** (HttpOnly + Secure(prod) + `__Host-`) — default-deny over default-allow
   * (SPEC §2). Shipping a client-readable cookie therefore requires an explicit `class: 'app-data'`;
   * there is no name-guessing fallback that could fail open on an unrecognized credential name.
   */
  class?: CookieClass;
  domain?: string;
  expires?: Date | string;
  httpOnly?: boolean;
  maxAge?: number;
  // SPEC §9.1.1:856 — CHIPS partitioning is correctness-critical for cross-site
  // (`SameSite=None`) login in an embedded/third-party context: Chrome requires the
  // `Partitioned` attribute or it refuses/segregates the cookie. The typed builder
  // must be able to emit it so `forwardBetterAuthSetCookie` round-trips it (part-3 I1).
  partitioned?: boolean;
  path?: string;
  // RFC 6265bis cookie priority. Modeled so the typed builder re-emits it instead of
  // silently dropping an attribute Better Auth set (part-3 I1).
  priority?: 'high' | 'low' | 'medium';
  /**
   * Force the credential `Secure` floor on, or request an audited downgrade off (SPEC §6.6/§9.1).
   *
   * `true` forces `Secure` regardless of `NODE_ENV` — e.g. behind a TLS-terminating proxy that
   * reports a dev request URL. `false` requests suppression of the floor; on a `session`/`auth`
   * cookie that is an insecure downgrade routed through the SAME KV432 gate as `secure: false`
   * (bugz-3 M1), so it is rejected unless recorded via {@link unsafeCookie} — an un-audited insecure
   * credential cookie is inexpressible. When omitted, `Secure` is engaged by the bootstrap-pinned
   * operator production posture (`NODE_ENV === 'production'`) or by an HTTPS-request signal
   * (`secure: true`), so the floor never depends solely on the env string (bugz-3 L1) while
   * localhost-http dev still works.
   */
  productionSecure?: boolean;
  sameSite?: 'lax' | 'none' | 'strict';
  secure?: boolean;
  /**
   * The audited downgrade escape for a `session`/`auth`-class cookie (SPEC §6.6/§9.1). When present,
   * an intentional weakening of the floor is recorded as a downgrade fact instead of being rejected
   * with KV432. Construct via {@link unsafeCookie}.
   */
  unsafe?: UnsafeCookieDowngrade;
}

UnsafeCookieDowngrade#

An opaque audited cookie-floor downgrade receipt minted only by {@link unsafeCookie}.

Signature

ts
interface UnsafeCookieDowngrade extends UnsafeCookieDowngradeInput {
  readonly [unsafeCookieDowngradeBrand]: { readonly kind: 'unsafe-cookie-downgrade' };
}

UnsafeCookieDowngradeInput#

The audited escape for an intentional insecure downgrade of a session/auth-class cookie (SPEC §6.6/§9.1). Produced by {@link unsafeCookie}; recorded as a downgrade fact for kovo explain cookies instead of being rejected with KV432.

Signature

ts
interface UnsafeCookieDowngradeInput {
  /** Which floor attribute(s) the author is intentionally weakening. */
  downgrade: {
    httpOnly?: boolean;
    sameSite?: 'lax' | 'none' | 'strict';
    secure?: boolean;
  };
  /** A required human justification, surfaced in `kovo explain cookies`. */
  justification: string;
}

CsrfAnonymousCookieOptions#

Anonymous CSRF binding cookie settings for sessionless mutation forms (SPEC §6.6).

Signature

ts
interface CsrfAnonymousCookieOptions {
  maxAge?: number;
  name?: string;
  path?: string;
  sameSite?: 'lax' | 'none' | 'strict';
  secure?: boolean;
}

CsrfOptions#

CSRF config: a secret, a session extractor, and optional anonymous form binding.

Signature

ts
interface CsrfOptions<Request> {
  /** Configure or disable the anonymous CSRF cookie used for a genuinely anonymous request. */
  anonymousCookie?: CsrfAnonymousCookieOptions | false;
  /** Form field name used as the default signing audience when no narrower sink audience is supplied. */
  field?: string;
  secret: SigningSecret;
  /**
   * Return the request's stable opaque 1..1,024-character session/rotation id, or `undefined` only
   * when the request is anonymous. A framework-resolved authenticated session that returns
   * `undefined`, a non-string/empty id, or an id longer than 1,024 characters fails closed.
   */
  sessionId: (request: Request) => string | undefined;
  /**
   * Allowlist of cross-origin origins permitted to make unsafe-verb requests (SPEC §6.6/§9.1). Each
   * entry is an absolute origin (e.g. `'https://app.example.com'`). The same-origin host is always
   * trusted; this list adds the legitimate cross-origin callers (split front-end, native shell) that
   * the header-based CSRF floor would otherwise reject. Flows from `createApp({ csrf })`.
   */
  trustedOrigins?: readonly string[];
}

MintedCsrfField#

A rendered CSRF hidden field plus the anonymous binding cookie the response must set, when needed.

Signature

ts
interface MintedCsrfField extends MintedCsrfToken {
  /** The configured CSRF field name. */
  field: string;
  /** Hidden `<input>` HTML carrying {@link token}. */
  html: string;
}

MintedCsrfToken#

A minted CSRF token plus the anonymous binding cookie the response must set, when needed.

Signature

ts
interface MintedCsrfToken {
  /** The synchronizer token to send back in the configured CSRF field. */
  token: string;
  /**
   * Exact first-anonymous binding cookie for non-Kovo response integrations. A managed, authorized
   * `createRequestHandler()` endpoint captures and delivers it during final response reconstruction.
   */
  setCookie?: string;
}

CspAllowlist#

App-facing third-party origins that extend, but never replace, Kovo's strict per-resource defaults. Uncensused origins must use {@link CspAllowlistOrigin} so the reviewed rationale is explicit; hardening directives such as base-uri and object-src are not configurable here.

Signature

ts
interface CspAllowlist {
  /** Extra origins admitted for `connect-src` (XHR/fetch/WebSocket/EventSource/beacon). */
  connectSrc?: readonly CspAllowlistEntry[];
  /** Extra origins admitted for `font-src`. */
  fontSrc?: readonly CspAllowlistEntry[];
  /** Extra origins admitted for `frame-src` (embedded `<iframe>` sources). */
  frameSrc?: readonly CspAllowlistEntry[];
  /** Extra origins admitted for `img-src` (external image hosts/CDNs). */
  imgSrc?: readonly CspAllowlistEntry[];
  /** Extra origins admitted for `media-src`. */
  mediaSrc?: readonly CspAllowlistEntry[];
  /** Extra origins admitted for `script-src` (third-party SDKs). */
  scriptSrc?: readonly CspAllowlistEntry[];
  /** Extra origins admitted for `style-src` (external stylesheet hosts). */
  styleSrc?: readonly CspAllowlistEntry[];
  /** Extra origins admitted for `worker-src`. */
  workerSrc?: readonly CspAllowlistEntry[];
}

CspAllowlistEntry#

A census-matched origin or an explicit reviewed escape.

Signature

ts
type CspAllowlistEntry = string | CspAllowlistOrigin;

CspAllowlistOrigin#

One reviewed CSP origin that cannot be connected to a static compiler census entry.

Signature

ts
interface CspAllowlistOrigin {
  /** Canonical absolute HTTP(S)/WS(S) origin admitted by the reviewed escape. */
  origin: string;
  /** Non-empty audit reason for admitting an origin absent from the static census. */
  rationale: string;
}

CspInlineMetadata#

CSP hash metadata for inline scripts/styles generated during document assembly.

Signature

ts
interface CspInlineMetadata {
  /** Stable CSP hashes for generated inline `<script>` bodies in document order. */
  scripts: readonly string[];
  /** Stable CSP hashes for generated inline `<style>` bodies in document order. */
  styles: readonly string[];
  /** Stable CSP hashes for rendered `style="..."` attribute values in document order. */
  styleAttributes?: readonly string[];
}

CspReportingConfig#

Options for the framework-owned CSP reporting group.

Signature

ts
interface CspReportingConfig {
  /**
   * Reporting API cache lifetime in seconds. Defaults to 10886400 seconds (126 days),
   * matching common browser examples for long-lived reporting groups.
   */
  maxAgeSeconds?: number;
}

DocumentCspConfig#

SF (secure-framework Tier 3): the strict default-on CSP configuration carried on a document response. allowlist extends the per-fetch directives; trustedTypes opts into the Chromium-only Trusted Types floor.

Signature

ts
interface DocumentCspConfig {
  allowlist?: CspAllowlist;
  /**
   * Enable COOP/COEP/CORP only when the generated posture proves there are no external resources,
   * frames, popups, opaque URLs, or dynamic browser fetch/worker effects.
   */
  crossOriginIsolation?: true;
  /**
   * OPP-14 / SPEC §6.6 audit-only telemetry: omitted/`{}` emits a framework-owned
   * Reporting API group and CSP `report-to` directive for the strict enforced policy.
   * Set `false` to opt out. Reports are runtime audit signals, not by-construction
   * security and not a report-only ramp.
   */
  reporting?: CspReportingConfig | false;
  /**
   * SF (secure-framework Tier 3): the Chromium-only Trusted Types floor, now DEFAULT-ON.
   * Omitted/`true` emits `require-trusted-types-for 'script'` plus the two private Kovo
   * policy names; set
   * `false` to opt OUT (e.g. an app embedding a third-party widget that needs its own
   * un-named TT policy, or that writes raw HTML through a sink Kovo does not route).
   */
  trustedTypes?: boolean;
}

RedosPatternError#

Thrown when pattern(...) uses regex syntax outside the linear matcher subset (KV434).

Signature

ts
class RedosPatternError extends Error {
  readonly code = 'KV434' as const;

  constructor(message: string) {
    super(`KV434 ${message}`);
    this.name = 'RedosPatternError';
  }
}

BlessedFormatName#

The name of a blessed, backtracking-free string format.

Signature

ts
type BlessedFormatName = keyof typeof BLESSED_FORMATS;

UnsafeRegexBrand#

A regex brand carrying the audited ReDoS-risk acceptance from {@link unsafeRegex}.

Signature

ts
interface UnsafeRegexBrand {
  readonly [unsafeRegexBrand]: { readonly kind: 'unsafe-regex' };
  readonly justification: string;
  readonly regex: RegExp;
  readonly unsafe: true;
}

@kovojs/server/signing#

Task: Validated signing key-ring construction and key lifecycle types.

Source: packages/server/src/public-signing.ts

Values#

createSigningKeyRing#

Create an opaque root-key ring with exactly one active key.

Signature

ts
function createSigningKeyRing(options: SigningKeyRingOptions): SigningKeyRing;

Supporting types#

ActiveSigningKey#

A key that may create new outputs. Exactly one ring entry is active.

Signature

ts
interface ActiveSigningKey {
  readonly id: string;
  readonly secret: string | Uint8Array;
  readonly state: 'active';
  readonly acceptUntil?: never;
}

FrameworkCsrfSigningSecret#

Opaque first-party CSRF/live-target authority carrier.

Signature

ts
interface FrameworkCsrfSigningSecret {
  readonly [frameworkCsrfSigningSecretBrand]: 'framework-csrf-signing-secret';
}

PreviousSigningKey#

A key accepted only until a finite overlap deadline.

Signature

ts
interface PreviousSigningKey {
  readonly acceptUntil: number;
  readonly id: string;
  readonly secret: string | Uint8Array;
  readonly state: 'previous';
}

RevokedSigningKey#

A revoked key retains only its public identifier, never secret bytes.

Signature

ts
interface RevokedSigningKey {
  readonly acceptUntil?: never;
  readonly id: string;
  readonly secret?: never;
  readonly state: 'revoked';
}

SigningKey#

One root-key lifecycle declaration.

Signature

ts
type SigningKey = ActiveSigningKey | PreviousSigningKey | RevokedSigningKey;

SigningKeyRing#

Opaque root-key configuration carrier.

The ring deliberately has no generic sign, verify, derive, seal, or open method. Framework sinks exchange it for a fixed-purpose handle inside crypto-authority.ts (SPEC §6.6 C9/C13).

Signature

ts
interface SigningKeyRing {
  readonly currentKeyId: string;
  readonly [signingKeyRingBrand]: 'kovo-signing-key-ring';
}

SigningKeyRingOptions#

Declarative configuration for constructing an opaque {@link SigningKeyRing}.

Signature

ts
interface SigningKeyRingOptions {
  /** Complete bounded rotation set; exactly one key must be `active`. */
  readonly keys: readonly SigningKey[];
}

SigningKeyState#

Lifecycle state for one framework root in a {@link SigningKeyRing}.

Signature

ts
type SigningKeyState = 'active' | 'previous' | 'revoked';

SigningSecret#

Accepted root configuration for fixed framework cryptographic sinks.

Signature

ts
type SigningSecret =
  | string
  | Uint8Array
  | SigningKeyRing
  | SigningKeyRingOptions
  | FrameworkCsrfSigningSecret;

@kovojs/server/sqlite#

Task: Experimental single-principal SQLite runtime with framework-owned native database construction.

Source: packages/server/src/sqlite.ts

Values#

createSqliteAppRuntime#

Create the opt-in SQLite starter runtime without giving generated source filesystem, native driver, raw SQL, or database-construction authority.

Compiler-bound metadata authenticates the exact table identities before any additional Drizzle schema callback, filesystem operation, or native database creation. The framework then derives a finite SQLite DDL subset and inserts optional seed rows with bound parameters. SQLite remains single-principal/local-development only; this constructor does not claim an engine authorization or confidentiality boundary (SPEC §6.6/§10.3).

Signature

ts
function createSqliteAppRuntime(
  options: KovoSqliteAppRuntimeOptions,
): Readonly<KovoSqliteAppRuntime>;

Supporting types#

KovoSqliteSeedValue#

A primitive accepted by the parameterized SQLite starter seed path.

Signature

ts
type KovoSqliteSeedValue = string | number | bigint | boolean | null;

KovoSqliteSeed#

One table plus rows inserted through the framework-owned parameterized seed sink.

Signature

ts
interface KovoSqliteSeed {
  /** A table present in the exact `tables` array passed to the runtime constructor. */
  table: unknown;
  /** Dense own-data rows keyed by physical SQLite column name. */
  rows: readonly Readonly<Record<string, KovoSqliteSeedValue>>[];
}

KovoSqliteAppRuntimeOptions#

Options for the experimental single-principal SQLite app runtime.

Signature

ts
interface KovoSqliteAppRuntimeOptions {
  /** Structured seed data; raw DDL/SQL is intentionally not an accepted authority. */
  seed?: readonly KovoSqliteSeed[];
  /** Exact Drizzle SQLite tables used for DDL and compiler-bound security metadata. */
  tables: readonly unknown[];
}

KovoSqliteDbProvider#

Opaque provider accepted by createApp({ db }) without exposing raw Drizzle methods.

Signature

ts
type KovoSqliteDbProvider = AppDbProvider<BetterSQLite3Database>;

KovoSqliteAppRuntime#

Frozen handles produced by the experimental single-principal SQLite runtime.

Signature

ts
interface KovoSqliteAppRuntime {
  /** Close the framework-owned in-memory native client. */
  close(): void;
  /** Opaque framework provider token. It is not callable and has no raw/native DB properties. */
  readonly db: KovoSqliteDbProvider;
  /** Volatile development-only mutation replay truth. Production rejects it. */
  readonly mutationReplayStore: MutationReplayStore;
  /** Volatile development-only principal revocation authority. */
  readonly principalEpochStore: PrincipalEpochStore;
  /** Read-only query/endpoint database with SQLite secret boxing applied. */
  readonly readonlyDb: Reader<BetterSQLite3Database>;
  /** SQLite setup is synchronous; this promise preserves the starter's uniform boot shape. */
  readonly ready: Promise<void>;
}

@kovojs/server/static-export#

Task: Static app export execution, policy, and diagnostics.

Source: packages/server/src/public-static-export.ts

Values#

exportStaticApp#

Pre-render an app only after a supported runner established the request-safe realm lock. Standalone build scripts use @kovojs/server/runtime-bootstrap as their literal first import (SPEC §6.6/§9.5).

Signature

ts
function exportStaticApp(
  app: KovoApp,
  options: StaticExportOptions = {},
): Promise<StaticExportResult>;

Supporting types#

StaticExportError#

Error thrown when static export is configured to fail on non-exportable routes.

Signature

ts
class StaticExportError extends Error {
  readonly code: DiagnosticCode | 'KV229';
  readonly diagnostics: readonly StaticExportDiagnostic[];

  constructor(diagnostics: readonly StaticExportDiagnostic[]) {
    const registered = registeredStaticExportDiagnostics(diagnostics, 'static-export error');
    super(
      registered.length === 1
        ? registered[0]!.message
        : `KV229 static export found ${registered.length} non-exportable routes.`,
    );
    this.name = 'StaticExportError';
    this.code = registered[0]?.code ?? 'KV229';
    this.diagnostics = witnessFreeze(registered);
  }
}

StaticExportCompileDiagnostic#

A compiler-emitted diagnostic evaluated against the static-export gate (SPEC §11.3): its code, source fileName, optional start position and help, and message. Input to the public {@link assertStaticExportCompileDiagnostics} and {@link blockingStaticExportDiagnostics}, which fail static export on error-severity codes.

Signature

ts
interface StaticExportCompileDiagnostic extends RegisteredDiagnostic<DiagnosticCode> {
  fileName: string;
  help?: string;
  start?: { column: number; line: number };
}

StaticExportDiagnostic#

Route-level diagnostic emitted when a request-shell route cannot be represented by static export output (SPEC §11.3).

concretePath, when present, names the single non-exportable concrete URL the diagnostic describes (e.g. a param route's individual staticPaths entry). SPEC §9.5 skip policy publishes the exportable subset, so skip must suppress only the exact non-exportable concrete target — not every sibling that shares the route pattern (routePath). Route-level diagnostics with no single concrete target leave concretePath undefined.

Signature

ts
interface StaticExportDiagnostic extends RegisteredDiagnostic<DiagnosticCode> {
  concretePath?: string;
  routePath: string;
}

StaticExportDiagnosticSeverity#

Severity label used when formatting static-export diagnostics.

Signature

ts
type StaticExportDiagnosticSeverity = 'ERROR' | 'WARN';

StaticExportNonExportablePolicy#

Policy for StaticExportOptions.onNonExportable: 'error' fails the export when a route cannot be statically rendered, 'skip' omits it (SPEC.md §12).

Signature

ts
type StaticExportNonExportablePolicy = 'error' | 'skip';

StaticExportOptions#

Options for exporting a KovoApp request shell to static route documents.

Signature

ts
interface StaticExportOptions {
  assets?: readonly {
    contentType?: string;
    headers?: HeadersInit;
    path: string;
    source: string | URL;
  }[];
  diagnostics?: readonly import('./static-export-diagnostics.js').StaticExportCompileDiagnostic[];
  onNonExportable?: StaticExportNonExportablePolicy;
  origin?: string;
  outDir?: string | URL;
  /** URL pathname base used to map referenced public assets back to the local root (SPEC §9.5). */
  publicAssetBase?: string;
  /** Local directory containing Vite-copied public assets referenced by exported HTML (SPEC §9.5). */
  publicAssetRoot?: string | URL;
}

StaticExportResult#

Static export output produced by exportStaticApp().

Signature

ts
interface StaticExportResult {
  artifacts: readonly {
    body: string;
    headers: Record<string, string>;
    path: string;
    status: number;
  }[];
  assets: readonly {
    headers: Record<string, string>;
    path: string;
    source: string;
    status: number;
  }[];
  clientModules: readonly {
    body: string;
    headers: Record<string, string>;
    href: string;
    path: string;
    status: number;
  }[];
  diagnostics: readonly import('./static-export-diagnostics.js').StaticExportDiagnostic[];
}

@kovojs/server/storage-downloads#

Task: Capability-protected storage download endpoint construction.

Source: packages/server/src/public-storage-downloads.ts

Values#

DEFAULT_CAPABILITY_DOWNLOAD_BASE_PATH#

Default mount path for the framework-owned storage download route.

Signature

ts
const DEFAULT_CAPABILITY_DOWNLOAD_BASE_PATH = '/_kovo/storage';

createStorageDownloadEndpoint#

Build the framework-owned storage download route as a prefix-mounted GET/HEAD endpoint(). The handler is the VERIFY SINK: it re-derives the expected key/method/scope from the request and runs verifyCapability BEFORE any storage read; on any failure it fails closed (generic 404, object never read, reason never leaked). This is what makes a stored object un-dereferenceable without a verifying token (SPEC §6.6, by-construction at the sink).

Parameter Type Description
options StorageDownloadEndpointOptions The storage to read from, the signing secret, the mount basePath, an optional request-derived scope, an optional replayStore for one-time tokens, and a clock.
(returns) EndpointDeclaration<string, 'GET', 'prefix'> A prefix-mounted GET/HEAD EndpointDeclaration.

Signature

ts
function createStorageDownloadEndpoint(
  options: StorageDownloadEndpointOptions,
): EndpointDeclaration<string, 'GET', 'prefix'>;

Supporting types#

SignUrlContext#

The ctx.signUrl capability added to the route request context (SPEC §6.6 / §9.1).

Signature

ts
interface SignUrlContext {
  /**
   * Mint a signed, short-lived, scope-bound capability URL for a stored object, pointing at the
   * framework download route. Canonicalize-before-sign: the signed key is the normalized key the
   * route re-derives, so the URL is not dereferenceable for any other object. Records a capability
   * fact for `kovo explain capabilities`.
   */
  signUrl(options: SignUrlOptions): Promise<SignedUrl>;
}

SignUrlOptions#

Options accepted by ctx.signUrl(...): the storage key plus the capability claims to mint.

Signature

ts
interface SignUrlOptions {
  /** Framework-minted storage object key. Bare strings and forged structures are refused. */
  key: ScopedKey;
  /** The HTTP method the URL authorizes. Downloads are reads; defaults to `GET`. */
  method?: CapabilityMethod;
  /** Optional scope binding (tenant/principal id) folded into the signature and re-checked at the sink. */
  scope?: string;
  /** Time-to-live in ms. Short by default (`DEFAULT_CAPABILITY_TTL_MS`) — a leaked URL is a bearer secret. */
  expiresIn?: number;
  /** When true, the URL is single-use: the sink burns it in the replay store on first dereference. */
  oneTime?: boolean;
}

SignedUrl#

The minted capability URL plus the claims it encodes.

Signature

ts
interface SignedUrl {
  /** The absolute-path URL (mount base + url-encoded key + `?kovo-cap=<token>`) to hand a client. */
  url: string;
  /** The opaque capability token embedded in {@link url}. */
  token: string;
  /** The storage object key (canonicalized) the URL authorizes. */
  key: ScopedKey;
  /** Whether the URL is single-use. */
  oneTime: boolean;
}

StorageDownloadEndpointOptions#

Options for the framework-owned storage download route.

Signature

ts
interface StorageDownloadEndpointOptions {
  /** The storage capability the verified handler reads from (AFTER the verify sink passes). */
  storage: StorageReadCapability;
  /** The framework signing secret the token is verified against (NOT app/per-request controlled). */
  secret: SigningSecret;
  /** Mount path; the route is `prefix`-mounted here. Defaults to `/_kovo/storage`. */
  basePath?: string;
  /** The scope the sink derives from the request and re-checks against the token's claim. */
  scope?: (request: Request) => string | undefined;
  /**
   * A one-time replay store; REQUIRED in production and to honor `oneTime` tokens. Production
   * accepts only createPostgresAppRuntimeDb().capabilityReplayStore.
   */
  replayStore?: CapabilityReplayStore;
  /** Persistent revocation authority. Required whenever `scope` derives a principal. */
  principalEpochStore?: PrincipalEpochStore;
  /** Development/test-only injectable clock (epoch ms); production refuses it. */
  now?: () => number;
  /** Disposition/filename forwarded to `respond.storedFile` AFTER verification (server-sniffed type). */
  storedFile?: Pick<RouteStoredFileOptions, 'disposition' | 'filename'>;
}

CapabilityMethod#

HTTP method a capability token authorizes. Downloads are reads; we model GET/HEAD.

Signature

ts
type CapabilityMethod = 'GET' | 'HEAD';

CapabilityReplayStore#

A replay store for one-time capability tokens: returns true iff this token id was unused.

Signature

ts
interface CapabilityReplayStore {
  /**
   * Atomically mark `id` consumed until the token's absolute expiry; return true if it was
   * previously unconsumed (first use). Stores that cannot honor expiry should fail closed outside
   * this interface rather than retaining replay ids for an unrelated horizon.
   */
  consume(id: string, expiresAt: number): boolean | Promise<boolean>;
}

@kovojs/server/storage-keys#

Task: Server-side scoped storage key derivation.

Source: packages/server/src/public-storage-keys.ts

Values#

scopedKey#

Bind an application key to the framework-authenticated principal on this request.

The principal is read from Kovo's private request snapshot, never from an app-supplied id. An anonymous or unresolved request therefore cannot accidentally collapse into a shared namespace.

Signature

ts
function scopedKey(request: unknown, key: string): ScopedKey;

@kovojs/server/tasks#

Task: Durable task declarations, scheduling, and status observation.

Source: packages/server/src/public-tasks.ts

Values#

task#

Declare a durable background function (SPEC §9.6). Tasks are registry entries with typed serialized input; task bodies may perform external I/O, but DB access composes through ctx.runQuery/ctx.runMutation rather than receiving a raw transactional db.

Signature

ts
function task<InputSchema extends Schema<unknown>, Value = unknown>(
  definition: Omit<TaskDefinition<string, InputSchema, Value>, 'key'>,
): TaskDefinition<string, InputSchema, Value>;
function task<
  const Key extends string,
  InputSchema extends Schema<unknown>,
  Value = unknown,
>(
  key: Key,
  definition: Omit<TaskDefinition<Key, InputSchema, Value>, 'key'>,
): TaskDefinition<Key, InputSchema, Value>;

createDurableTaskStatus#

Framework-owned, operator-only inspection facade for durable tasks (SPEC §9.6). It reads the persisted job rows directly for deployed Postgres artifacts, or a read-only snapshot in memory tests, and redacts serialized args and failure text unless callers explicitly request them for privileged diagnostics.

Signature

ts
function createDurableTaskStatus(
  source: DurableTaskStatusSnapshotSource | DurableTaskStatusSqlExecutor,
): DurableTaskStatusSurface;

Supporting types#

TaskCronCatchUp#

Catch-up policy for task-declared recurring schedules (SPEC §9.6).

Signature

ts
type TaskCronCatchUp = 'skip' | 'backfill';

TaskDefinition#

A typed durable background function declaration (SPEC §9.6).

Signature

ts
interface TaskDefinition<
  Key extends string = string,
  InputSchema extends Schema<unknown> = Schema<unknown>,
  Value = unknown,
> {
  /** Five-field UTC cron expression for recurring task materialization (SPEC §9.6). */
  cron?: string;
  /** Missed-occurrence policy. Defaults to `skip`; `backfill` is bounded by the materializer. */
  catchUp?: TaskCronCatchUp;
  /** Serialized args for recurring invocations. Defaults to `{}`. */
  cronArgs?: InferSchema<InputSchema>;
  input: InputSchema;
  key: Key;
  maxGenerations?: number;
  priority?: number;
  concurrency?: number;
  retry?: {
    backoff?: 'exponential' | 'linear';
    maxAttempts?: number;
  };
  run(args: InferSchema<InputSchema>, context: TaskRunContext): Promise<Value> | Value;
  timeoutMs?: number;
}

TaskFactory#

App-scoped task factory. createApp() uses this to contextually type task declarations.

Signature

ts
interface TaskFactory {
  <InputSchema extends Schema<unknown>, Value = unknown>(
    definition: Omit<TaskDefinition<string, InputSchema, Value>, 'key'>,
  ): TaskDefinition<string, InputSchema, Value>;
  <const Key extends string, InputSchema extends Schema<unknown>, Value = unknown>(
    key: Key,
    definition: Omit<TaskDefinition<Key, InputSchema, Value>, 'key'>,
  ): TaskDefinition<Key, InputSchema, Value>;
}

TaskHandle#

Stable handle returned by request.schedule(task, args) for later cancellation.

Signature

ts
interface TaskHandle<Key extends string = string> {
  readonly id: string;
  readonly task: Key;
}

TaskInput#

Serialized input type accepted by request.schedule(task, args).

Signature

ts
type TaskInput<Task> =
  Task extends TaskDefinition<string, infer InputSchema, unknown>
    ? InferSchema<InputSchema>
    : never;

TaskPrincipalReadScope#

Read-only task scope returned by ctx.actAs(id) or ctx.declareSystemRead(reason).

SPEC §10.3 DEC-G: durable tasks have no ambient request principal, so owner-scoped reads must name an explicit principal or audited system posture before entering the query runtime.

Signature

ts
interface TaskPrincipalReadScope {
  /** Bind a stateful-sink key to this framework-minted principal scope. */
  stateKey(key: string): ScopedKey;
  runQuery<const Query extends TaskRunnableQuery<unknown>>(
    definition: Query,
    input: TaskRunnableQueryInput<Query>,
  ): Promise<unknown>;
}

TaskPrincipalScope#

Read/write task scope returned by ctx.actAs(id) for work derived to a single owner principal (SPEC §10.3 DEC-G).

Signature

ts
interface TaskPrincipalScope extends TaskPrincipalReadScope, TaskPrincipalWriteScope {}

TaskPrincipalWriteScope#

Write-only task scope returned by ctx.actAs(id) or ctx.declareSystemWrite(reason).

SPEC §10.3 DEC-G: durable tasks have no ambient request principal, so owner-scoped writes must name an explicit principal or audited system posture before entering the mutation runtime.

Signature

ts
interface TaskPrincipalWriteScope {
  /** Bind a stateful-sink key to this framework-minted principal scope. */
  stateKey(key: string): ScopedKey;
  runMutation<const Mutation extends TaskRunnableMutation<unknown>>(
    definition: Mutation,
    input: TaskRunnableMutationInput<Mutation>,
  ): Promise<unknown>;
}

TaskRunContext#

Context available to durable task bodies (SPEC §9.6: composition only, no raw db).

Tasks do not receive db or a transaction handle. Writes compose through ctx.runMutation(...), and reads compose through ctx.runQuery(...), so durable background work reuses the audited mutation/query channels instead of importing a broad app DB handle.

Signature

ts
interface TaskRunContext {
  /** One-based execution attempt for this durable job, including the current lease claim. */
  readonly attempt: number;
  readonly jobId: string;
  /** Stable idempotency key for external APIs; equal to the durable job id (SPEC §9.6). */
  readonly idempotencyKey: string;
  /** Aborts when the runner loses this lease or reaches the task deadline. */
  readonly signal: AbortSignal;
  readonly fetch: typeof globalThis.fetch;
  /**
   * SPEC §10.3 DEC-G: choose the owner principal for scoped background work. Payload fields do
   * not become authority unless task code explicitly derives and validates this id first.
   */
  actAs(principalId: string): TaskPrincipalScope;
  /** SPEC §10.3 DEC-G: audited cross-owner read posture for genuine system work. */
  declareSystemRead(reason: string): TaskPrincipalReadScope;
  /** SPEC §10.3 DEC-G: audited cross-owner write posture for genuine system work. */
  declareSystemWrite(reason: string): TaskPrincipalWriteScope;
  /** Bind genuine cross-principal task state to the finite durable-task-system posture. */
  systemStateKey(key: string): ScopedKey;
  runMutation<const Mutation extends TaskRunnableMutation<unknown>>(
    definition: Mutation,
    input: TaskRunnableMutationInput<Mutation>,
  ): Promise<unknown>;
  runQuery<const Query extends TaskRunnableQuery<unknown>>(
    definition: Query,
    input: TaskRunnableQueryInput<Query>,
  ): Promise<unknown>;
  schedule<const Task extends TaskDefinition<string, Schema<unknown>, unknown>>(
    definition: Task,
    args: TaskInput<Task>,
    options?: TaskScheduleOptions,
  ): Promise<TaskHandle<Task['key']>>;
}

TaskRunnableMutation#

Minimal public shape of a mutation accepted by TaskRunContext.runMutation(...).

Signature

ts
interface TaskRunnableMutation<Input = unknown> {
  input: Schema<Input>;
  key: string;
}

TaskRunnableMutationInput#

Input type accepted by TaskRunContext.runMutation(...) for a mutation-like definition.

Signature

ts
type TaskRunnableMutationInput<Mutation> =
  Mutation extends TaskRunnableMutation<infer Input> ? Input : never;

TaskRunnableQuery#

Minimal public shape of a query accepted by TaskRunContext.runQuery(...).

Signature

ts
interface TaskRunnableQuery<Input = unknown> {
  args?: Schema<Input>;
  key: string;
}

TaskRunnableQueryInput#

Input type accepted by TaskRunContext.runQuery(...) for a query-like definition.

Signature

ts
type TaskRunnableQueryInput<Query> = Query extends { args: Schema<infer Input> }
  ? Input
  : undefined;

TaskScheduleOptions#

Scheduling options for durable task jobs (SPEC §9.6).

Signature

ts
interface TaskScheduleOptions {
  /** Run no earlier than this many milliseconds after the enclosing transaction commits. */
  afterMs?: number;
  /** Run no earlier than this wall-clock time. Mutually exclusive with `afterMs`. */
  at?: Date | string | number;
  /** Logical identity for replacing or throttling a still-ready pending job. */
  key?: ScopedKey;
  /** Key coalescing mode. Defaults to debounce: latest args and latest run time win. */
  coalesce?: 'debounce' | 'throttle';
}

TaskSchedulingRequest#

Mutation request helpers for durable task scheduling (SPEC §9.6).

Signature

ts
interface TaskSchedulingRequest {
  cancel(handle: TaskHandle): Promise<boolean>;
  schedule<const Task extends TaskDefinition<string, Schema<unknown>, unknown>>(
    definition: Task,
    args: TaskInput<Task>,
    options?: TaskScheduleOptions,
  ): Promise<TaskHandle<Task['key']>>;
}

DurableTaskObservedStatus#

Persisted durable-task job states visible through the SPEC §9.6 status surface.

Signature

ts
type DurableTaskObservedStatus =
  | 'ready'
  | 'running'
  | 'succeeded'
  | 'failed'
  | 'dead'
  | 'cancelled';

DurableTaskStatusFilters#

Filters accepted by the operator-only durable-task status surface. Pagination and selector inputs are runtime-bounded so an accidentally request-exposed inspector cannot issue an unbounded _kovo_jobs scan.

Signature

ts
interface DurableTaskStatusFilters {
  readonly ids?: readonly string[];
  readonly task?: string;
  readonly status?: DurableTaskObservedStatus | readonly DurableTaskObservedStatus[];
  readonly limit?: number;
  readonly offset?: number;
  /**
   * Args and failure text are intentionally redacted by default because scheduled task
   * payloads and thrown errors commonly carry customer data or external-provider secrets
   * (SPEC §9.6).
   */
  readonly includeArgs?: boolean;
}

DurableTaskStatusJob#

Unredacted job snapshot consumed by createDurableTaskStatus(...).

Signature

ts
interface DurableTaskStatusJob {
  readonly id: string;
  readonly task: string;
  readonly args: unknown;
  readonly runAt: Date;
  readonly status: DurableTaskObservedStatus;
  readonly attempts: number;
  readonly createdAt: Date;
  readonly updatedAt: Date;
  readonly key?: string | ScopedKey;
  readonly lastError?: string;
  readonly leasedUntil?: Date;
  readonly leaseOwner?: string;
}

DurableTaskStatusRecord#

Redacted job record returned by the durable-task status surface.

Signature

ts
interface DurableTaskStatusRecord {
  readonly id: string;
  readonly task: string;
  readonly status: DurableTaskObservedStatus;
  readonly attempts: number;
  readonly runAt: Date;
  readonly createdAt: Date;
  readonly updatedAt: Date;
  readonly args?: unknown;
  readonly key?: string;
  readonly lastError?: string;
  readonly leasedUntil?: Date;
  readonly leaseOwner?: string;
}

DurableTaskStatusSnapshotSource#

Read-only in-memory source for durable-task status inspection in tests/tools.

Signature

ts
interface DurableTaskStatusSnapshotSource {
  snapshot(): readonly DurableTaskStatusJob[];
}

DurableTaskStatusSqlExecutor#

Minimal SQL executor required to inspect deployed _kovo_jobs rows (SPEC §9.6).

Signature

ts
interface DurableTaskStatusSqlExecutor {
  execute<Row = Record<string, unknown>>(
    statement: DurableTaskStatusSqlStatement,
  ): Promise<DurableTaskStatusSqlResult<Row>>;
}

DurableTaskStatusSqlResult#

Row result shape returned by a durable-task status SQL executor.

Signature

ts
interface DurableTaskStatusSqlResult<Row = Record<string, unknown>> {
  readonly rows: readonly Row[];
}

DurableTaskStatusSqlStatement#

Parameterized SQL statement emitted by the durable-task status reader.

Signature

ts
interface DurableTaskStatusSqlStatement {
  readonly text: string;
  readonly values: readonly unknown[];
}

DurableTaskStatusSurface#

Framework-owned, operator-only durable-task status reader for SPEC §9.6 visibility.

Signature

ts
interface DurableTaskStatusSurface {
  get(
    handle: TaskHandle | string,
    options?: Pick<DurableTaskStatusFilters, 'includeArgs'>,
  ): Promise<DurableTaskStatusRecord | undefined>;
  list(filters?: DurableTaskStatusFilters): Promise<DurableTaskStatusRecord[]>;
  listFailures(
    filters?: Omit<DurableTaskStatusFilters, 'status'>,
  ): Promise<DurableTaskStatusRecord[]>;
}

AppTaskDeclaration#

Task declaration shape accepted by createApp({ tasks }) and stored on KovoApp (SPEC §9.6).

Signature

ts
type AppTaskDeclaration<_AppRequest = unknown> = TaskDefinition<
  string,
  Schema<unknown>,
  unknown
>;

@kovojs/server/vite#

Task: The Vite plugin that serves authored Kovo apps through the app shell in development and build.

Source: packages/server/src/vite-source.ts

Values#

kovo#

Workspace source-mode adapter; production consumers use the published vite.mjs entry.

Signature

ts
function kovo(options: KovoVitePluginOptions): KovoVitePlugin;

Supporting types#

KovoVitePlugin#

Opaque Vite plugin token returned by {@link kovo}; place it in a vite.config.ts plugins array.

Signature

ts
interface KovoVitePlugin {
  /** Stable plugin name used by Vite diagnostics. */
  readonly name: 'kovo';
}

KovoVitePluginOptions#

Options for the public Kovo Vite plugin (SPEC.md §9.5).

Signature

ts
interface KovoVitePluginOptions {
  /** Authored app module id to load in Vite dev; it must default-export a KovoApp. */
  app: string;
}

@kovojs/server/webhooks#

Task: Webhook declarations, replay protection, and transaction contracts.

Source: packages/server/src/public-webhooks.ts

Values#

createMemoryWebhookReplayStore#

Create an in-memory webhook replay store for local development and tests.

The store implements SPEC §10.3's reservation shape: reserve() atomically claims one authenticated provider-event identity, concurrent get() calls wait for the committed response, committed truth retires at its exact event horizon, and pending truth never auto-expires.

Signature

ts
function createMemoryWebhookReplayStore(
  options: { maxEntries?: number; maxPending?: number } = {},
): WebhookReplayStore;

webhook#

Declare a webhook endpoint: a path-first POST receiver that verifies the raw payload signature before parsing input, then runs a handler that can record domain changes and is idempotent by construction. Until compiler-derived export identities are available, the registry/replay name is derived from the declared path. Pass a WebhookVerifier built from generic helpers such as hmacSignature, or verify: 'none' with a justification (SPEC §9.1).

Parameter Type Description
path Path The webhook receiver path.
definition WebhookDefinition<InputSchema, Value, Tx, Writes> The verify, input schema, and handler (plus optional idempotency/transaction).
(returns) WebhookDeclaration<Path, Path, InputSchema, Value, Tx, Writes> A WebhookDeclaration (a verified EndpointDeclaration).

Copyable example

ts
import { domain, s } from '@kovojs/server'
import { webhook } from '@kovojs/server/webhooks';

const order = domain('order');

export const orderPaid = webhook('/webhooks/order-paid', {
  verify: 'none',
  verifyJustification: 'internal test fixture',
  input: s.object({ orderId: s.string() }),
  writes: [order],
  handler(input, context) {
    return { changes: [context.recordChange(order, { keys: [input.orderId] })] };
  },
});

Signature

ts
function webhook<
  const Path extends string,
  InputSchema extends Schema<unknown>,
  Value = unknown,
  Tx = unknown,
  const Writes extends WebhookDeclaredWrites | undefined = undefined,
>(
  path: Path,
  definition: WebhookDefinition<InputSchema, Value, Tx, Writes>,
): WebhookDeclaration<Path, Path, InputSchema, Value, Tx, Writes>;

webhookReplayIdentity#

Create an opaque replay identity from authenticated provider payload fields (SPEC §9.1/§10.3).

occurredAtMs must come from the verified event payload, never local receipt time or an HMAC delivery timestamp. Kovo validates the fixed 30-day horizon and five-minute future-skew ceiling after verification and parsing, before any replay-store call or handler execution.

Signature

ts
function webhookReplayIdentity(key: string, occurredAtMs: number): WebhookReplayIdentity;

Supporting types#

WebhookChangeOptions#

Options for WebhookHandlerContext.recordChange (SPEC §9.1): the affected keys, an optional override input, and a reason, used to build the unified {domain, keys, input} change record emitted after commit.

Signature

ts
interface WebhookChangeOptions<Input = unknown> {
  input?: Input;
  keys?: readonly string[];
  reason?: string;
}

WebhookDeclaration#

The registry-visible endpoint declaration returned by {@link webhook} (SPEC §9.1): an EndpointDeclaration for a POST exact mount, tagged webhook: true with the resolved webhookDefinition, so the webhook appears in the machine-ingress audit.

Signature

ts
interface WebhookDeclaration<
  Name extends string = string,
  Path extends string = string,
  InputSchema extends Schema<unknown> = Schema<unknown>,
  Value = unknown,
  Tx = unknown,
  Writes extends WebhookDeclaredWrites | undefined = WebhookDeclaredWrites,
> extends EndpointDeclaration<Path, 'POST', 'exact'> {
  access?: AccessDecision;
  name: Name;
  webhook: true;
  webhookDefinition: WebhookDefinition<InputSchema, Value, Tx, Writes>;
}

WebhookDeclaredWriteDomain#

Domain accepted by WebhookHandlerContext.recordChange. SPEC §9.1 requires webhook writes to be declared so kovo explain endpoints cannot under-report machine-ingress invalidation.

Signature

ts
type WebhookDeclaredWriteDomain<Writes extends WebhookDeclaredWrites | undefined> = Domain<
  WebhookDeclaredWriteKey<Writes>
>;

WebhookDeclaredWriteKey#

Domain keys a webhook may record from its declared writes list. If a webhook declares no writes, recordChange has no valid domain key.

Signature

ts
type WebhookDeclaredWriteKey<Writes extends WebhookDeclaredWrites | undefined> =
  Writes extends readonly Domain<infer DomainKey>[] ? DomainKey : never;

WebhookDeclaredWrites#

Declared domain writes for a webhook. Used by {@link WebhookDefinition.writes} and {@link WebhookHandlerContext.recordChange} so the TypeScript surface mirrors the SPEC §9.1 endpoint audit contract.

Signature

ts
type WebhookDeclaredWrites = readonly Domain[];

WebhookDefinition#

The definition object accepted by {@link webhook} (SPEC §9.1 webhook lifecycle): the verify scheme (a WebhookVerifier or 'none' with a verifyJustification), loose input schema, optional idempotency/replayStore/transaction, and the handler. Types webhook()'s parameter.

Signature

ts
type WebhookDefinition<
  InputSchema extends Schema<unknown> = Schema<unknown>,
  Value = unknown,
  Tx = unknown,
  Writes extends WebhookDeclaredWrites | undefined = undefined,
> = {
  access?: AccessDecision;
  handler: (
    input: InferSchema<InputSchema> & Record<string, unknown>,
    context: WebhookHandlerContext<InferSchema<InputSchema> & Record<string, unknown>, Tx, Writes>,
  ) => Promise<Value | WebhookFail> | (Value | WebhookFail);
  idempotency?: (
    input: InferSchema<InputSchema> & Record<string, unknown>,
  ) => WebhookReplayIdentity | undefined;
  input: InputSchema;
  replayStore?: WebhookReplayStore;
  transaction?: <Result>(
    context: WebhookTransactionContext<InferSchema<InputSchema> & Record<string, unknown>>,
    run: (tx: Tx) => Promise<Result>,
  ) => Promise<Result>;
  writes?: Writes;
} & (
  | {
      verify: WebhookVerifier;
      verifyJustification?: never;
    }
  | {
      verify: 'none';
      verifyJustification: string;
    }
);

WebhookFail#

A typed webhook failure outcome (SPEC §9.1 webhook lifecycle): a declared error code and payload answered with the chosen 4xx/5xx status (optional retryAfter) so provider retry semantics are explicit. Produced via WebhookHandlerContext.fail, which rolls back the transaction.

Signature

ts
interface WebhookFail<Code extends string = string, Payload = unknown> {
  error: {
    code: Code;
    payload: Payload;
  };
  ok: false;
  retryAfter?: number;
  status: 400 | 401 | 422 | 429 | 500;
}

WebhookFailureStatus#

HTTP statuses a typed webhook failure response may carry (SPEC §9.1).

Signature

ts
type WebhookFailureStatus = 400 | 401 | 422 | 429 | 500;

WebhookHandlerContext#

The context passed to a webhook handler (SPEC §9.1 webhook lifecycle): the transaction handle tx, verified rawBody, the raw request, fail to return a typed {@link WebhookFail}, and recordChange to emit a declared domain change record.

Signature

ts
interface WebhookHandlerContext<
  Input,
  Tx = unknown,
  Writes extends WebhookDeclaredWrites | undefined = WebhookDeclaredWrites,
> {
  /**
   * Framework-owned positive HTTP egress capability (SPEC §6.6). Every initial and redirect
   * origin must be declared by `egress.allowDestinations`; the resolved-IP floor still applies.
   */
  readonly fetch: typeof globalThis.fetch;
  fail<Code extends string, Payload>(
    code: Code,
    payload: Payload,
    options?: { retryAfter?: number; status?: 400 | 401 | 422 | 429 | 500 },
  ): WebhookFail<Code, Payload>;
  /**
   * SPEC §10.3 DEC-G: choose the owner principal for scoped webhook writes. A provider payload
   * field is not authority unless handler code derives and validates this id before calling actAs.
   */
  actAs(principalId: string): WebhookPrincipalWriteScope<Tx>;
  /** SPEC §10.3 DEC-G: audited cross-owner write posture for genuine system webhook work. */
  declareSystemWrite(reason: string): WebhookPrincipalWriteScope<Tx>;
  rawBody: Uint8Array;
  recordChange<const DomainKey extends WebhookDeclaredWriteKey<Writes>, ChangeInput = Input>(
    domain: Domain<DomainKey>,
    options?: WebhookChangeOptions<ChangeInput>,
  ): ChangeRecord<DomainKey, ChangeInput | Input>;
  request: EndpointRequest;
  runMutation<const Mutation extends WebhookRunnableMutation<any>>(
    definition: Mutation,
    input: WebhookRunnableMutationInput<Mutation>,
  ): Promise<unknown>;
  tx: WebhookTxDb<Tx>;
}

WebhookPrincipalWriteScope#

Write scope returned by context.actAs(id) or context.declareSystemWrite(reason) in a webhook handler. SPEC §10.3 DEC-G requires machine ingress to choose an explicit owner principal or audited system posture before using mutation composition or the transaction DB handle.

Signature

ts
interface WebhookPrincipalWriteScope<Tx = unknown> {
  runMutation<const Mutation extends WebhookRunnableMutation<any>>(
    definition: Mutation,
    input: WebhookRunnableMutationInput<Mutation>,
  ): Promise<unknown>;
  tx: WebhookTxDb<Tx>;
}

WebhookReplayIdentity#

Framework-proven replay identity for one authenticated provider event (SPEC §9.1/§10.3).

Construct with {@link webhookReplayIdentity} from the provider event key and the event's own authenticated occurrence timestamp. The immutable facts are passed intact to replay stores so committed truth can retire at the fixed 30-day horizon without ever expiring an ambiguous in-flight claim. The private brand is author-time ergonomics only; runtime provenance is held in a module-private WeakMap, so casts and structural clones are rejected.

Signature

ts
interface WebhookReplayIdentity {
  /** Exclusive replay-retention deadline derived from `occurredAtMs` by the framework. */
  readonly expiresAtMs: number;
  /** Provider event key, scoped by the source-derived webhook identity in the replay store. */
  readonly key: string;
  /** Authenticated event occurrence time in Unix epoch milliseconds. */
  readonly occurredAtMs: number;
  readonly [webhookReplayIdentityBrand]: 'webhook-replay-identity';
}

WebhookReplayReservation#

A held webhook replay reservation, committed with the final response or aborted on failure.

Signature

ts
interface WebhookReplayReservation {
  /** Release a pending reservation without committing, so a retry can re-run the handler (A4). */
  abort?(): Promise<void> | void;
  commit(response: WebhookWireResponse): Promise<void> | void;
}

WebhookReplayStore#

Atomic idempotency store used by writable webhooks to reserve and replay provider events.

Signature

ts
interface WebhookReplayStore {
  get(
    scope: string,
    identity: WebhookReplayIdentity,
  ): Promise<WebhookWireResponse | undefined> | WebhookWireResponse | undefined;
  reserve(
    scope: string,
    identity: WebhookReplayIdentity,
  ): Promise<WebhookReplayReservation | undefined> | WebhookReplayReservation | undefined;
  set(
    scope: string,
    identity: WebhookReplayIdentity,
    response: WebhookWireResponse,
  ): Promise<void> | void;
}

WebhookResponseStatus#

HTTP status union accepted by webhook replay wire responses (SPEC §9.1 / §10.3).

Signature

ts
type WebhookResponseStatus = WebhookFailureStatus | WebhookSuccessStatus;

WebhookRunnableMutation#

Minimal public shape accepted by WebhookHandlerContext.runMutation(...) (SPEC §9.1/§10.3).

Signature

ts
interface WebhookRunnableMutation<Input = unknown> {
  input: Schema<Input>;
  key: string;
}

WebhookRunnableMutationInput#

Input accepted by WebhookHandlerContext.runMutation(...) for a mutation-like definition.

Signature

ts
type WebhookRunnableMutationInput<Mutation> =
  Mutation extends WebhookRunnableMutation<infer Input> ? Input : never;

WebhookSuccessStatus#

HTTP status a successful webhook replay response stores and replays (SPEC §9.1).

Signature

ts
type WebhookSuccessStatus = 200;

WebhookTransactionContext#

The context passed to a webhook's transaction wrapper (SPEC §9.1 webhook lifecycle), carrying the parsed input, verified rawBody, and raw request so the app can open the BEGIN/COMMIT boundary around the handler.

Signature

ts
interface WebhookTransactionContext<Input> {
  input: Input;
  rawBody: Uint8Array;
  request: EndpointRequest;
}

WebhookTxDb#

Transaction-scoped DB handle threaded by the webhook lifecycle (SPEC §10.3). It preserves the app DB provider's write surface but hides the raw .transaction() opener; the private-symbol brand makes a raw app DB or long-lived module handle awkward to pass where the handler expects the framework-owned transaction capability.

This is an author-time guardrail only (SPEC §6.6): webhook idempotency posture, transaction ordering, SQL provenance, and fail-closed sinks remain the enforcement. Casts/any can forge the type and must not be treated as proof.

Signature

ts
type WebhookTxDb<Db> = (Db extends object
  ? Omit<Db, '$client' | 'client' | 'pglite' | 'session' | 'sqlite' | 'transaction'>
  : Db) & {
  readonly [webhookTxDbBrand]: {
    readonly db: Db;
    readonly scope: 'webhook-transaction';
  };
};

WebhookWireResponse#

A stored wire response replayed for a duplicate webhook delivery (SPEC §10.3).

Signature

ts
interface WebhookWireResponse extends ServerResponseBase<
  string,
  ResponseHeaders,
  WebhookResponseStatus
> {}

@kovojs/server/write-safety#

Task: Explicit server-derived and trusted assignment write evidence.

Source: packages/server/src/public-write-safety.ts

Values#

serverValue#

Assert that value is a server-derived (non-request-input) value flowing into a governed column (SPEC §11.1, KV438). Runtime-transparent: returns value unchanged. The analyzer discharges KV438 only when it independently proves value literal or private/server-derived. Request input and opaque computations both fail closed: neither serverValue(input.role, …) nor serverValue(helper(input.role), …) can launder provenance. Use {@link trustedAssign} for a deliberately reviewed opaque server computation.

Parameter Type Description
value T The server-derived value being written.
reason string A short justification, surfaced in review.
(returns) T value, unchanged.

Copyable example

ts
import { serverValue } from '@kovojs/server/write-safety';

declare const db: any;
declare const input: { userId: string };
declare const users: any;

await db.insert(users).values({ id: input.userId, role: serverValue('member', 'default role') });

Signature

ts
function serverValue<T>(value: T, reason: string): T;

trustedAssign#

The audited privileged-write escape (SPEC §11.1, KV438): deliberately write a value — even a request-input value — to a governed column (e.g. an admin setting another user's role). Runtime-transparent: returns value unchanged, and records an audit fact for kovo explain capabilities. Louder than {@link serverValue} because it admits input.

Parameter Type Description
value T The value being written to the governed column.
obligation TrustedAssignObligation A required structured invariant/basis/evidence record, recorded for audit.
(returns) T value, unchanged.

Copyable example

ts
import { trustedAssign } from '@kovojs/server/write-safety';

declare const db: any;
declare const input: { role: string };
declare const users: any;

await db.update(users).set({
  role: trustedAssign(input.role, {
    evidence: {
      digest: 'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
      kind: 'test',
      reference: 'tests/authz/admin-role-grant',
    },
    invariant: 'governed-write.authorized-principal',
    why: { guard: 'guards.role:admin', kind: 'guard-chain' },
  }),
});

Signature

ts
function trustedAssign<T>(value: T, obligation: TrustedAssignObligation): T;

Supporting types#

TrustedAssignEvidence#

Digest-bound evidence offered for second-party review of a privileged write.

Signature

ts
interface TrustedAssignEvidence {
  readonly digest: `sha256:${string}`;
  readonly kind: 'policy-review' | 'test';
  /** Stable test/policy locator, not explanatory prose. */
  readonly reference: string;
}

TrustedAssignInvariant#

The only invariant trustedAssign may assert (SPEC §§6.6, 10.3, 11.1).

Signature

ts
type TrustedAssignInvariant = 'governed-write.authorized-principal';

TrustedAssignObligation#

Structured review obligation for the trustedAssign KV438 escape.

This shape is author-time ergonomics only. The runtime chokepoint and build analyzer both independently validate the exact closed grammar (SPEC §§6.6, 10.3, 11.1).

Signature

ts
interface TrustedAssignObligation {
  readonly evidence: TrustedAssignEvidence;
  readonly invariant: TrustedAssignInvariant;
  readonly why: TrustedAssignWhy;
}

TrustedAssignWhy#

A machine-addressable reason an exceptional governed write remains authorized.

Signature

ts
type TrustedAssignWhy =
  | {
      /** Exact guard/policy binding reviewed at the call site. */
      readonly guard: string;
      readonly kind: 'guard-chain';
    }
  | {
      readonly kind: 'policy';
      /** Stable external policy identifier, not explanatory prose. */
      readonly policy: string;
    };