Browse documentation

Runtime contracts

Low-level policy, result, adapter and pipeline APIs for custom runtimes and third-party adapters.

Most apps should use defineAdmin, createFlowpanel, and the generated UI. This page documents the lower-level @flowpanel/core contracts for adapter authors, custom framework integrations and security-sensitive extensions.

import {
  accessAllows,
  assertWritableInput,
  authorizeOperation,
  bindAdapterScope,
  resolveScopeApplier,
  errorResult,
  filterReadableProjection,
  reportUnexpectedError,
  resolveOperationAccess,
  resultResponse,
  FLOWPANEL_ERROR_STATUS,
  type AccessContext,
  type AccessRule,
  type AdminDefinition,
  type AdminPaths,
  type AdminPathsInput,
  type AnyResourceConfig,
  type AdapterScopeContext,
  type BoundAdapterScope,
  type ErrorContext,
  type FieldAccess,
  type FieldAccessMap,
  type FieldWriteContext,
  type FlowpanelErrorCode,
  type FlowpanelResult,
  type FlowpanelResultError,
  type FlowpanelResultMeta,
  type FlowpanelWarning,
  type FlowpanelWarningCode,
  type JsonValue,
  type ResourceAccess,
  type ResourceOperation,
} from "@flowpanel/core";

Definitions and paths

AdminDefinition<Resources> is the immutable public input accepted by defineAdmin; AnyResourceConfig is its generic resource constraint. AdminPathsInput is the partial { admin, api } input and AdminPaths is the normalized resolved pair. Both paths have a leading slash and no trailing slash.

Application code normally relies on inference and never writes these types explicitly. They are useful when a factory returns a definition:

function companyAdmin(): AdminDefinition {
  return {
    adapter,
    auth,
    paths: { admin: "/ops", api: "/api/ops" },
  };
}

Access and field policy

AccessRule is a boolean, role string, role list, or predicate receiving AccessContext (session, role, scope). ResourceAccess maps those rules to the four ResourceOperation values: read, create, update, delete.

  • accessAllows(rule, context) evaluates one normalized rule.
  • resolveOperationAccess(access, requireRole, operation) applies precedence: the operation-specific rule wins, then the compatibility requireRole.
  • authorizeOperation(rule, context) throws the safe access error when the resolved rule rejects the request.

FieldAccess<Row> adds read, write and sensitive policy. A FieldAccessMap<Row> maps it by field name; write predicates receive FieldWriteContext<Row> with both the current row and submitted input.

  • filterReadableProjection(fields, policy, context) removes fields the caller may not read before the adapter query is built.
  • assertWritableInput(input, knownFields, policy, context) rejects unknown, sensitive or forbidden writes. It does not silently drop them.

Bound adapter scope

A tenant policy crosses the runtime/adapter boundary as an opaque BoundAdapterScope. Create it with bindAdapterScope(apply). Adapters must apply it to list, get, update and delete operations and fail closed when a resource requires scope but no binding is present.

resolveScopeApplier(ctx) is that fail-closed rule, shared by the first-party adapters: it returns the bound predicate, null when the resource declares none, and throws FlowpanelAccessError when one is required but missing. An adapter that resolves scope by hand must refuse the query in the same case.

Post-commit effects

Post-commit audit, realtime or revalidation failures do not turn a committed mutation into a false failure. They appear as a FlowpanelWarning in result metadata; FlowpanelWarningCode is audit_failed, realtime_failed, or revalidation_failed.

Result envelope

Every protected controller and v1 JSON CRUD endpoint returns FlowpanelResult<T>:

type FlowpanelResult<T> =
  | { ok: true; data: T; meta: FlowpanelResultMeta }
  | { ok: false; error: FlowpanelResultError };

FlowpanelResultMeta carries the request id and optional warnings. FlowpanelResultError carries a stable FlowpanelErrorCode, a safe message, optional field errors and request id. FLOWPANEL_ERROR_STATUS is the canonical code-to-HTTP-status table.

  • errorResult(error, requestId) converts known errors to the envelope and redacts unexpected failures to internal.
  • resultResponse(result) produces a JSON Response with the canonical status.
  • reportUnexpectedError(error, context, onError) invokes hooks.onError at most once for the same error object. ErrorContext includes request, operation, actor, IP and user-agent diagnostics but no submitted secrets.

These helpers are public for runtime authors. Ordinary actions should throw a documented FlowPanel error or return an ActionResult, then let the built-in runtime normalize it.

Generated-UI form, drawer, action, import, restore and SSE routes predate the v1 client protocol and keep their compact, route-specific response shapes for compatibility. Use createFlowpanelClient or protected controllers when a custom surface needs the structured envelope above.