Dyrecteddyrected
API Reference

Workflow Reference

Workflow states, capabilities, revisions, lifecycle events, and generated public contracts.

Workflows model editorial state transitions separately from ordinary field edits. A workflow-enabled document can keep an editable working revision while exposing an independent public snapshot, so changing a published entry does not necessarily change what public readers see.

Use publishingWorkflow() for the standard draft → review → publish lifecycle. Define a custom workflow only when the business process genuinely has different states, capabilities, or transition rules.

States, transitions, and capabilities

A transition names its allowed source and destination states. Capabilities determine who may view drafts, submit, publish, reject, or perform other configured actions. Enforce these rules on the server; hiding an unavailable button is only presentation.

import { defineCollection, publishingWorkflow } from '@dyrected/core'

export const Articles = defineCollection({
  slug: 'articles',
  workflow: publishingWorkflow(),
  fields: [
    { name: 'title', type: 'text', label: 'Title', required: true },
    { name: 'body', type: 'richText', label: 'Body', required: true },
  ],
})

Revisions and concurrency

Workflow metadata includes a revision. Pass expectedRevision when transitioning from an editor that may be stale. A rejected concurrency check is preferable to silently overwriting another editor's decision.

Draft visibility

Draft visibility and public materialization are distinct concerns. Use canViewWorkflowDraft and configured capabilities rather than inferring access from a user role in frontend code. Test anonymous, author, reviewer, and publisher behavior explicitly.

Transition hooks

Use beforeTransition to validate or reject a state change before it commits. Use afterTransition for notifications and revalidation after persistence. Design external effects to tolerate retries and partial downstream failure.

See Workflows, Editorial Approval, and Migrating to Workflows.

Lifecycle events

Lifecycle events provide durable dispatch helpers for effects that should not depend on one request remaining alive. Treat event handlers as potentially retried: make them idempotent and record provider identifiers when duplicate delivery would be harmful.

SDK and REST

The SDK exposes transition and workflowHistory on fluent collection clients. REST exposes the corresponding transition and history routes only for workflow-enabled collections. Runtime OpenAPI contains project-specific paths and schemas.

Generated workflow and lifecycle contracts

availableWorkflowTransitions

Exported function from @dyrected/core.

export function availableWorkflowTransitions(
  workflow: WorkflowConfig,
  state: string,
  user?: AuthenticatedUser,
): WorkflowTransition[]

canViewWorkflowDraft

Exported function from @dyrected/core.

export function canViewWorkflowDraft(workflow: WorkflowConfig, user?: AuthenticatedUser): boolean

createLifecycleEvent

Exported function from @dyrected/core.

export function createLifecycleEvent(args: {
  name: LifecycleEventName;
  collection: string;
  documentId: string;
  actorId?: string;
  payload: Record<string, unknown>;
}): LifecycleEvent

createWorkflowDocument

Exported function from @dyrected/core.

export async function createWorkflowDocument(args: {
  config: DyrectedConfig;
  collection: CollectionConfig;
  data: Record<string, unknown>;
  user?: AuthenticatedUser;
}): Promise<{ doc: BaseDocument; event: LifecycleEvent }>

dispatchLifecycleEvent

Exported function from @dyrected/core.

export async function dispatchLifecycleEvent(config: DyrectedConfig, event: LifecycleEvent): Promise<void>

dispatchPendingLifecycleEvents

Exported function from @dyrected/core.

export async function dispatchPendingLifecycleEvents(config: DyrectedConfig, limit = 50): Promise<number>

initializeWorkflowDocument

Exported function from @dyrected/core.

export function initializeWorkflowDocument(data: Record<string, unknown>, workflow: WorkflowConfig)

LIFECYCLE_EVENTS_COLLECTION

Exported constant from @dyrected/core.

export const LIFECYCLE_EVENTS_COLLECTION = "__lifecycle_events";

LifecycleEvent

Exported interface from @dyrected/core.

export interface LifecycleEvent<TPayload = Record<string, unknown>> {
  id: string;
  name: LifecycleEventName;
  collection: string;
  documentId: string;
  occurredAt: string;
  actorId?: string;
  payload: TPayload;
  attempts: number;
  status: "pending" | "processing" | "delivered" | "failed";
  nextAttemptAt?: string;
  deliveredAt?: string;
  lastError?: string;
}
MemberSignatureDescription
idid: string
namename: LifecycleEventName
collectioncollection: string
documentIddocumentId: string
occurredAtoccurredAt: string
actorIdactorId?: string
payloadpayload: TPayload
attemptsattempts: number
statusstatus: "pending" | "processing" | "delivered" | "failed"
nextAttemptAtnextAttemptAt?: string
deliveredAtdeliveredAt?: string
lastErrorlastError?: string

LifecycleEventHandler

Exported type from @dyrected/core.

export type LifecycleEventHandler = (
  event: LifecycleEvent,
) => void | Promise<void>;

LifecycleEventName

Exported type from @dyrected/core.

export type LifecycleEventName = (typeof LIFECYCLE_EVENT_NAMES)[number];

materializeWorkflowDocument

Exported function from @dyrected/core.

export function materializeWorkflowDocument(
  doc: BaseDocument,
  workflow: WorkflowConfig,
  user?: AuthenticatedUser,
): BaseDocument | null

publishingWorkflow

Exported function from @dyrected/core.

export function publishingWorkflow(): WorkflowConfig

saveWorkflowDraft

Exported function from @dyrected/core.

export async function saveWorkflowDraft(args: {
  config: DyrectedConfig;
  collection: CollectionConfig;
  id: string;
  originalDoc: BaseDocument;
  data: Record<string, unknown>;
  user?: AuthenticatedUser;
}): Promise<{ doc: BaseDocument; event: LifecycleEvent }>

transitionWorkflow

Exported function from @dyrected/core.

export async function transitionWorkflow(args: {
  config: DyrectedConfig;
  collection: CollectionConfig;
  id: string;
  transitionName: string;
  expectedRevision?: number;
  comment?: string;
  user?: AuthenticatedUser;
  req: HookRequestContext;
}): Promise<BaseDocument>

WORKFLOW_HISTORY_COLLECTION

Exported constant from @dyrected/core.

export const WORKFLOW_HISTORY_COLLECTION = "__workflow_history";

workflowCapabilities

Exported function from @dyrected/core.

export function workflowCapabilities(workflow: WorkflowConfig, user?: AuthenticatedUser): Set<string>

WorkflowConfig

Exported interface from @dyrected/core.

export interface WorkflowConfig<TDoc extends object = Record<string, unknown>> {
  initialState: string;
  /** State used for a new working revision created from published content. */
  draftState?: string;
  states: WorkflowState[];
  transitions: WorkflowTransition[];
  /** Maps values in `user.roles` to workflow capabilities. */
  roles?: WorkflowRole[];
  hooks?: {
    beforeTransition?: CollectionBeforeTransitionHook<TDoc>[];
    afterTransition?: CollectionAfterTransitionHook<TDoc>[];
  };
}
MemberSignatureDescription
initialStateinitialState: string
draftStatedraftState?: stringState used for a new working revision created from published content.
statesstates: WorkflowState[]
transitionstransitions: WorkflowTransition[]
rolesroles?: WorkflowRole[]Maps values in `user.roles` to workflow capabilities.
hookshooks?: { beforeTransition?: CollectionBeforeTransitionHook<TDoc>[]; afterTransition?: CollectionAfterTransitionHook<TDoc>[]; }

WorkflowMetadata

Exported interface from @dyrected/core.

export interface WorkflowMetadata {
  state: string;
  revision: number;
  publishedRevision?: number;
  publishedAt?: string;
  publishedBy?: string;
  /** Transitions currently allowed for the requesting user. Response-only. */
  availableTransitions?: string[];
}
MemberSignatureDescription
statestate: string
revisionrevision: number
publishedRevisionpublishedRevision?: number
publishedAtpublishedAt?: string
publishedBypublishedBy?: string
availableTransitionsavailableTransitions?: string[]Transitions currently allowed for the requesting user. Response-only.

WorkflowRole

Exported interface from @dyrected/core.

export interface WorkflowRole {
  /** Existing user role value, for example `editor` or `publisher`. */
  role: string;
  capabilities: string[];
}
MemberSignatureDescription
rolerole: stringExisting user role value, for example `editor` or `publisher`.
capabilitiescapabilities: string[]

WorkflowState

Exported interface from @dyrected/core.

export interface WorkflowState {
  /** Stable machine-readable state key. */
  name: string;
  /** Label rendered in the Admin UI. */
  label: string;
  /** Marks the state whose revision is visible to public readers. */
  published?: boolean;
  /** Optional visual tone used by the Admin UI. */
  color?: "neutral" | "warning" | "success" | "danger" | "info";
}
MemberSignatureDescription
namename: stringStable machine-readable state key.
labellabel: stringLabel rendered in the Admin UI.
publishedpublished?: booleanMarks the state whose revision is visible to public readers.
colorcolor?: "neutral" | "warning" | "success" | "danger" | "info"Optional visual tone used by the Admin UI.

WorkflowTransition

Exported interface from @dyrected/core.

export interface WorkflowTransition {
  /** Stable transition key used by the REST and SDK APIs. */
  name: string;
  label: string;
  from: string | string[];
  to: string;
  /** Every listed capability is required. */
  requiredCapabilities?: string[];
  /** Require a non-empty comment when performing the transition. */
  requireComment?: boolean;
  /** Remove the public snapshot after this transition commits. */
  unpublish?: boolean;
}
MemberSignatureDescription
namename: stringStable transition key used by the REST and SDK APIs.
labellabel: string
fromfrom: string | string[]
toto: string
requiredCapabilitiesrequiredCapabilities?: string[]Every listed capability is required.
requireCommentrequireComment?: booleanRequire a non-empty comment when performing the transition.
unpublishunpublish?: booleanRemove the public snapshot after this transition commits.

WorkflowTransitionContext

Exported interface from @dyrected/core.

export interface WorkflowTransitionContext<
  TDoc extends object = Record<string, unknown>,
> {
  transition: WorkflowTransition;
  from: string;
  to: string;
  doc: TDoc;
  user?: AuthenticatedUser;
  comment?: string;
  req: HookRequestContext;
  db: DatabaseAdapter;
}
MemberSignatureDescription
transitiontransition: WorkflowTransition
fromfrom: string
toto: string
docdoc: TDoc
useruser?: AuthenticatedUser
commentcomment?: string
reqreq: HookRequestContext
dbdb: DatabaseAdapter

On this page