Workflow
@granit/workflow provides framework-agnostic types and API functions for a finite
state machine — mirroring Granit.Workflow on the .NET backend. It models entity
lifecycle through named states, guarded transitions, and optional approval routing.
@granit/react-workflow wraps these into a provider and hooks that manage status
fetching, transition execution, and paginated audit history.
Peer dependencies: axios, @granit/logger, react ^19
Package structure
Section titled “Package structure”Directory@granit/workflow/ FSM types, transition/history API functions (framework-agnostic)
- @granit/react-workflow WorkflowProvider, status/transition/history hooks
| Package | Role | Depends on |
|---|---|---|
@granit/workflow | DTOs, transition outcome enum, API functions | axios |
@granit/react-workflow | WorkflowProvider, useWorkflowStatus, useWorkflowTransition, useWorkflowHistory | @granit/workflow, @granit/logger, react |
import { WorkflowProvider } from '@granit/react-workflow';import { api } from './api-client';
function App({ children }) { return ( <WorkflowProvider apiClient={api} basePath="/api/v1/workflow"> {children} </WorkflowProvider> );}import { fetchStatus, executeTransition, fetchHistory } from '@granit/workflow';import type { WorkflowStatusDto, TransitionResultDto } from '@granit/workflow';TypeScript SDK
Section titled “TypeScript SDK”const TransitionOutcome = { Completed: 'Completed', ApprovalRequested: 'ApprovalRequested', Denied: 'Denied', InvalidTransition: 'InvalidTransition',} as const;
type TransitionOutcomeValue = (typeof TransitionOutcome)[keyof typeof TransitionOutcome];
const WorkflowLifecycleStatus = { Draft: 0, PendingReview: 1, Published: 2, Archived: 3,} as const;
type WorkflowLifecycleStatusValue = (typeof WorkflowLifecycleStatus)[keyof typeof WorkflowLifecycleStatus];interface TransitionDto { readonly targetState: string; readonly name: string; readonly allowed: boolean; readonly requiresApproval: boolean;}
interface TransitionRequestDto { readonly targetState: string; readonly comment?: string;}
interface TransitionResultDto { readonly succeeded: boolean; readonly resultingState: string; readonly outcome: TransitionOutcomeValue;}
interface TransitionHistoryDto { readonly previousState: string; readonly newState: string; readonly transitionedAt: string; readonly transitionedBy: string; readonly comment: string | null;}
interface WorkflowStatusDto { readonly currentState: string; readonly availableTransitions: TransitionDto[];}
interface WorkflowHistoryPage { items: TransitionHistoryDto[]; totalCount: number; nextCursor: string | null;}API functions
Section titled “API functions”| Function | Endpoint | Description |
|---|---|---|
fetchStatus(client, basePath, entityType, entityId) | GET /{entityType}/{entityId}/transitions | Current state and available transitions |
executeTransition(client, basePath, entityType, entityId, request) | POST /{entityType}/{entityId}/transition | Trigger a transition |
fetchHistory(client, basePath, entityType, entityId, params?) | GET /{entityType}/{entityId}/history | Paginated transition history |
React bindings
Section titled “React bindings”WorkflowProvider
Section titled “WorkflowProvider”interface WorkflowProviderProps { apiClient: AxiosInstance; basePath?: string; // default: '/api/v1/workflow' children: React.ReactNode;}
<WorkflowProvider apiClient={api} basePath="/api/v1/workflow"> {children}</WorkflowProvider>useWorkflowStatus(options)
Section titled “useWorkflowStatus(options)”Fetches current state and available transitions for an entity.
interface UseWorkflowStatusReturn { readonly currentState: string | null; readonly transitions: TransitionDto[]; readonly loading: boolean; readonly error: Error | null; readonly refetch: () => Promise<void>;}useWorkflowTransition(options)
Section titled “useWorkflowTransition(options)”Executes a state transition with optional audit comment.
interface UseWorkflowTransitionOptions { entityType: string; entityId: string; onSuccess?: (result: TransitionResultDto) => void; onError?: (error: Error) => void;}
interface UseWorkflowTransitionReturn { readonly transition: (targetState: string, comment?: string) => Promise<TransitionResultDto | null>; readonly loading: boolean; readonly result: TransitionResultDto | null; readonly error: Error | null;}useWorkflowHistory(options)
Section titled “useWorkflowHistory(options)”Fetches paginated transition audit trail for an entity.
interface UseWorkflowHistoryOptions { entityType: string; entityId: string; enabled?: boolean; // default: true}
interface UseWorkflowHistoryReturn { readonly history: TransitionHistoryDto[]; readonly loading: boolean; readonly error: Error | null; readonly refetch: () => Promise<void>;}Transition lifecycle
Section titled “Transition lifecycle”graph LR
Fetch["Fetch status"] --> Check["Check transitions"]
Check --> Execute["Execute transition"]
Execute --> Result{"Outcome?"}
Result -->|Completed| Refetch["Refetch status"]
Result -->|ApprovalRequested| Pending["Pending approval"]
Result -->|Denied| Error["Show error"]
Approval routing
Section titled “Approval routing”When a transition has requiresApproval: true, calling executeTransition returns
outcome: 'ApprovalRequested' and the entity enters a pending state. An approver
must then complete or deny the transition via the same API.
Public API summary
Section titled “Public API summary”| Category | Key exports | Package |
|---|---|---|
| Enums | TransitionOutcome, WorkflowLifecycleStatus | @granit/workflow |
| Types | WorkflowStatusDto, TransitionDto, TransitionResultDto, TransitionHistoryDto | @granit/workflow |
| API functions | fetchStatus(), executeTransition(), fetchHistory() | @granit/workflow |
| Provider | WorkflowProvider, useWorkflowConfig() | @granit/react-workflow |
| Hooks | useWorkflowStatus(), useWorkflowTransition(), useWorkflowHistory() | @granit/react-workflow |
See also
Section titled “See also”- Granit.Workflow module — .NET FSM engine with publication lifecycle
- Timeline — Audit entries can reference workflow transitions
- Templating — Templates use
WorkflowLifecycleStatusfor publication lifecycle