Implementation:Langgenius Dify SyncWorkflowDraft
| Knowledge Sources | |
|---|---|
| Domains | Workflow API Graph Persistence |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
Concrete tool for persisting the current workflow graph state to the server, provided by the Dify workflow service layer. Includes both the sync function and its companion sanitization and hydration utilities.
Description
The sync workflow draft subsystem consists of three cooperating functions:
syncWorkflowDraft is the primary persistence function. It accepts the current graph state (nodes, edges, viewport), feature flags, and variable definitions, sanitizes the payload to remove non-serializable properties, and sends the cleaned data to the server via a POST request. The server responds with a CommonResponse augmented with an updated_at timestamp and a new hash for optimistic concurrency.
sanitizeWorkflowDraftPayload prepares the graph for transmission by iterating over all nodes and applying type-specific sanitization rules. Trigger Plugin nodes are reduced to their canonical field set (stripping any extra hydrated properties). Start nodes with json_object type variables have their json_schema normalized from string to object if needed.
hydrateWorkflowDraftResponse performs the inverse operation when loading drafts. It filters out temporary nodes and edges (those marked with _isTempNode or _isTemp), strips underscore-prefixed transient properties from data payloads, hydrates Trigger Plugin nodes with their schema and config fields, normalizes Start node variable schemas, and masks secret environment variable values as [__HIDDEN__].
Usage
Use syncWorkflowDraft whenever the editor needs to persist the current canvas state, such as during auto-save, explicit save actions, or before navigating away from the editor. Use sanitizeWorkflowDraftPayload directly if you need to prepare a payload without sending it. Use hydrateWorkflowDraftResponse after fetching a draft to transform the raw server response into a form suitable for the editor.
Code Reference
Source Location
- Repository: Dify
- Files:
web/service/workflow.ts(Lines 18-24) --syncWorkflowDraftweb/service/workflow-payload.ts(Lines 63-101) --sanitizeWorkflowDraftPayloadweb/service/workflow-payload.ts(Lines 140-193) --hydrateWorkflowDraftResponse
Signature
// Primary sync function
export const syncWorkflowDraft = ({ url, params }: {
url: string
params: Pick<FetchWorkflowDraftResponse,
'graph' | 'features' | 'environment_variables' | 'conversation_variables'>
}): Promise<CommonResponse & { updated_at: number, hash: string }>
// Sanitization utility
export const sanitizeWorkflowDraftPayload = (
params: WorkflowDraftSyncParams
): WorkflowDraftSyncParams
// Hydration utility
export const hydrateWorkflowDraftResponse = (
draft: FetchWorkflowDraftResponse
): FetchWorkflowDraftResponse
Import
import { syncWorkflowDraft } from '@/service/workflow'
import {
sanitizeWorkflowDraftPayload,
hydrateWorkflowDraftResponse,
} from '@/service/workflow-payload'
I/O Contract
Inputs (syncWorkflowDraft)
| Name | Type | Required | Description |
|---|---|---|---|
| url | string |
Yes | The draft sync endpoint URL, typically {prefix}/{appId}/workflows/draft.
|
| params.graph | { nodes: Node[], edges: Edge[], viewport: Viewport } |
Yes | The current graph state including all nodes, edges, and the canvas viewport. |
| params.features | Record<string, any> |
Yes | Feature flag configuration for the workflow. |
| params.environment_variables | EnvironmentVariable[] |
Yes | Workflow-scoped environment variables. |
| params.conversation_variables | ConversationVariable[] |
Yes | Per-conversation session state variables. |
Outputs (syncWorkflowDraft)
| Name | Type | Description |
|---|---|---|
| result | string |
Standard success/failure indicator from CommonResponse.
|
| updated_at | number |
Unix timestamp of when the draft was last updated on the server. |
| hash | string |
New optimistic concurrency token to be used in the next sync request. |
Inputs (sanitizeWorkflowDraftPayload)
| Name | Type | Required | Description |
|---|---|---|---|
| params | WorkflowDraftSyncParams |
Yes | The raw draft parameters containing graph, features, environment_variables, and conversation_variables. |
Outputs (sanitizeWorkflowDraftPayload)
| Name | Type | Description |
|---|---|---|
| params | WorkflowDraftSyncParams |
A sanitized copy with Trigger Plugin nodes reduced to canonical fields and Start node json_schema values normalized to objects. |
Dependencies
| Dependency | Purpose |
|---|---|
@/service/base (post) |
Provides the underlying HTTP POST helper for server communication. |
immer (produce) |
Used by hydrateWorkflowDraftResponse for immutable state transformation during draft hydration.
|
@/app/components/workflow/types (BlockEnum) |
Enum used to identify node types during sanitization (e.g., BlockEnum.TriggerPlugin, BlockEnum.Start).
|
Usage Examples
import { syncWorkflowDraft } from '@/service/workflow'
// Persist the current editor state
const response = await syncWorkflowDraft({
url: `/apps/${appId}/workflows/draft`,
params: {
graph: {
nodes: currentNodes,
edges: currentEdges,
viewport: { x: 0, y: 0, zoom: 1.0 },
},
features: currentFeatures,
environment_variables: envVars,
conversation_variables: convVars,
},
})
// Update the local hash for the next save
setCurrentHash(response.hash)
console.log('Draft saved at:', new Date(response.updated_at * 1000))