> ## Documentation Index
> Fetch the complete documentation index at: https://dripart-docs-custom-nodes-sdk-v2-frontend.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript workflow API

> Opening workflow data and applying host text replacements.

<Note>
  This page is generated from the authoritative declaration file. Do not edit it by hand. Contract SHA-256: <code>152c7fab547f</code>.
</Note>

This reference contains 5 exported declarations: `WorkflowData`, `WorkflowImportContext`, `WorkflowImportResult`, `WorkflowImporter`, `WorkflowHandle`.

Download the complete contract from the docs source: [TypeScript declaration](https://github.com/Comfy-Org/docs/blob/main/public/custom-nodes-sdk/v2/comfy-api.d.ts).

## Contract

```typescript theme={null}
// ─── workflowHandle.ts ───────────────────────────────────────────

/** Parsed ComfyUI workflow JSON. */
export type WorkflowData = Readonly<Record<string, unknown>>

export interface WorkflowImportContext {
  readonly name: string
  readonly type: string
}

export type WorkflowImportResult =
  | { readonly workflow: WorkflowData | string }
  | { readonly prompt: Readonly<Record<string, unknown>> | string }

export interface WorkflowImporter {
  /** Namespaced and unique within the pack. */
  readonly id: string
  readonly mimeTypes?: readonly string[]
  readonly extensions?: readonly string[]
  /** Per-file limit; the host-wide ceiling is 16 MiB. */
  readonly maxBytes: number
  enabled?(): boolean | Promise<boolean>
  parse(
    bytes: Uint8Array,
    context: WorkflowImportContext
  ):
    | WorkflowImportResult
    | null
    | undefined
    | Promise<WorkflowImportResult | null | undefined>
}

export interface WorkflowHandle {
  /** Replaces the active document with parsed ComfyUI workflow JSON. */
  open(data: WorkflowData): Promise<void>
  /** Returns the current saved-format workflow, bounded to 8 MiB. */
  snapshot(): Promise<WorkflowData>
  /** Registers a bounded worker-side parser for host-opened or dropped files. */
  registerImporter(importer: WorkflowImporter): Unsubscribe
  /** Expands the active document's `%date:...%` and `%Node.widget%` tokens. */
  applyTextReplacements(value: string): string
  /**
   * The active document's identity: a process-local id minted fresh each time
   * a workflow finishes loading — including a second load of the same file,
   * which gets a different id from the first. `undefined` before the first
   * workflow has loaded this page load.
   *
   * Distinct from the workflow's own saved identity (its file path, or the
   * `id` written into the workflow JSON): that one is meant to survive a
   * reload and compare equal across sessions. This one is the opposite by
   * design — it exists so a pack can tell "the document I was looking at got
   * replaced" from "the document I was looking at got edited", which
   * comparing graph contents cannot do, since editing IS mutating the graph
   * contents of the very document that is still current.
   *
   * Equivalent to `current()?.id`, and kept because reading the id is the
   * common case and does not need a handle.
   */
  documentId(): string | undefined
  /**
   * The document on screen, or `undefined` before one is open.
   *
   * A handle rather than the bare id when a pack needs to know what it is
   * looking at — the name to label its own UI, whether there are unsaved
   * edits, and whether a document it stored state for is still open.
   *
   * Read-only: opening has its own explicit call, and saving, closing and
   * renaming belong to the user.
   */
  current(): DocumentHandle | undefined
}
```
