UNPKG

@stable-canvas/comfyui-client

Version:

api Client for ComfyUI that supports both NodeJS and Browser environments. It provides full support for all RESTful / WebSocket APIs.

1,355 lines (1,329 loc) 843 kB
/** * Minimal `EventEmitter` interface that is molded against the Node.js * `EventEmitter` interface. */ declare class EventEmitter< EventTypes extends EventEmitter.ValidEventTypes = string | symbol, Context extends any = any > { static prefixed: string | boolean; /** * Return an array listing the events for which the emitter has registered * listeners. */ eventNames(): Array<EventEmitter.EventNames<EventTypes>>; /** * Return the listeners registered for a given event. */ listeners<T extends EventEmitter.EventNames<EventTypes>>( event: T ): Array<EventEmitter.EventListener<EventTypes, T>>; /** * Return the number of listeners listening to a given event. */ listenerCount(event: EventEmitter.EventNames<EventTypes>): number; /** * Calls each of the listeners registered for a given event. */ emit<T extends EventEmitter.EventNames<EventTypes>>( event: T, ...args: EventEmitter.EventArgs<EventTypes, T> ): boolean; /** * Add a listener for a given event. */ on<T extends EventEmitter.EventNames<EventTypes>>( event: T, fn: EventEmitter.EventListener<EventTypes, T>, context?: Context ): this; addListener<T extends EventEmitter.EventNames<EventTypes>>( event: T, fn: EventEmitter.EventListener<EventTypes, T>, context?: Context ): this; /** * Add a one-time listener for a given event. */ once<T extends EventEmitter.EventNames<EventTypes>>( event: T, fn: EventEmitter.EventListener<EventTypes, T>, context?: Context ): this; /** * Remove the listeners of a given event. */ removeListener<T extends EventEmitter.EventNames<EventTypes>>( event: T, fn?: EventEmitter.EventListener<EventTypes, T>, context?: Context, once?: boolean ): this; off<T extends EventEmitter.EventNames<EventTypes>>( event: T, fn?: EventEmitter.EventListener<EventTypes, T>, context?: Context, once?: boolean ): this; /** * Remove all listeners, or those of the specified event. */ removeAllListeners(event?: EventEmitter.EventNames<EventTypes>): this; } declare namespace EventEmitter { export interface ListenerFn<Args extends any[] = any[]> { (...args: Args): void; } export interface EventEmitterStatic { new < EventTypes extends ValidEventTypes = string | symbol, Context = any >(): EventEmitter<EventTypes, Context>; } /** * `object` should be in either of the following forms: * ``` * interface EventTypes { * 'event-with-parameters': any[] * 'event-with-example-handler': (...args: any[]) => void * } * ``` */ export type ValidEventTypes = string | symbol | object; export type EventNames<T extends ValidEventTypes> = T extends string | symbol ? T : keyof T; export type ArgumentMap<T extends object> = { [K in keyof T]: T[K] extends (...args: any[]) => void ? Parameters<T[K]> : T[K] extends any[] ? T[K] : any[]; }; export type EventListener< T extends ValidEventTypes, K extends EventNames<T> > = T extends string | symbol ? (...args: any[]) => void : ( ...args: ArgumentMap<Exclude<T, string | symbol>>[Extract<K, keyof T>] ) => void; export type EventArgs< T extends ValidEventTypes, K extends EventNames<T> > = Parameters<EventListener<T, K>>; export const EventEmitter: EventEmitterStatic; } declare namespace ComfyUiWsTypes { namespace Messages { interface Executed { node: string; display_node: string; output: Record<string, any>; prompt_id: string; timestamp: number; } interface ExecutionInterrupted { prompt_id: string; node_id: string; node_type: string; executed: string[]; } interface Executing { node: string; display_node: string; prompt_id: string; timestamp: number; } interface Progress { value: number; max: number; prompt_id: string; node: string; } interface ProgressState { prompt_id: string; nodes: Record<string, { value: number; max: number; state: string; node_id: string; display_node_id: string; parent_node_id: string | null; real_node_id: string; }>; } interface Status { status: { exec_info: { queue_remaining: number; }; }; } interface ExecutionStart { prompt_id: string; timestamp: number; } interface ExecutionError { prompt_id: string; node_id: string; node_type: string; executed: string[]; exception_message: string; exception_type: string; traceback: string; current_inputs: any; current_outputs: any[]; } interface ExecutionCached { nodes: string[]; prompt_id: string; timestamp: number; } interface ExecutionSuccess { prompt_id: string; timestamp: number; } } namespace BinaryMessages { interface ProgressText { nodeId: string; text: string; } interface BinaryPreviewWithMetadata { blob: Blob; nodeId: string; displayNodeId: string; parentNodeId: string; realNodeId: string; promptId: string; } } } type ComfyUIClientEvents = { status: [ComfyUiWsTypes.Messages.Status["status"] | null]; progress: [ComfyUiWsTypes.Messages.Progress]; progress_state: [ComfyUiWsTypes.Messages.ProgressState]; executing: [ComfyUiWsTypes.Messages.Executing]; executed: [ComfyUiWsTypes.Messages.Executed]; execution_interrupted: [ComfyUiWsTypes.Messages.ExecutionInterrupted]; execution_start: [ComfyUiWsTypes.Messages.ExecutionStart]; execution_error: [ComfyUiWsTypes.Messages.ExecutionError]; execution_cached: [ComfyUiWsTypes.Messages.ExecutionCached]; execution_success: [ComfyUiWsTypes.Messages.ExecutionSuccess]; connected: []; reconnected: []; reconnecting: []; /** * binary image preview * * from binary data sent by the server */ b_preview: [Blob]; b_preview_with_metadata: [ ComfyUiWsTypes.BinaryMessages.BinaryPreviewWithMetadata ]; /** * progress text * * from binary data sent by the server */ progress_text: [ComfyUiWsTypes.BinaryMessages.ProgressText]; /** * load image data from websocket */ image_data: [ { image: ArrayBuffer; mime: string; } ]; /** * get all messages */ message: [MessageEvent<any>]; /** * close client */ close: []; connection_error: [{ type: string; message: string; }]; /** * unhandled event message */ unhandled: [{ type: string; data: any; }]; }; type FnHook<N extends keyof Client = keyof Client, Fn extends Client[N] = Client[N]> = Fn extends (...args: any) => any ? { type: "function"; name: N; fn: (original: Fn, ...args: Parameters<Fn>) => ReturnType<Fn>; } : never; type PluginHook<N extends keyof Client = keyof Client, Fn extends Client[N] = Client[N]> = FnHook<N, Fn>; declare class Plugin { private hooks; install(instance: Client): void; protected addHook<N extends keyof Client = keyof Client, Fn extends Client[N] = Client[N]>(hook: PluginHook<N, Fn>): void; } declare namespace ComfyUIClientResponseTypes { export interface SystemStatsRoot { system: System; devices: Device[]; } export interface System { os: string; python_version: string; embedded_python: boolean; comfyui_version: string; pytorch_version: string; required_frontend_version?: string; argv: string[]; ram_total: number; ram_free: number; cloud_version?: string; comfyui_frontend_version?: string; workflow_templates_version?: string; } export interface Device { name: string; type: string; index: number; vram_total: number; vram_free: number; torch_vram_total: number; torch_vram_free: number; } interface NodeConfig { input: NodeInputs; output: Array<string[] | string>; output_is_list: boolean[]; output_name: string[]; name: string; display_name: string; description: string; category: string; output_node: boolean; } type NodeInputs = { required?: Record<string, NodeSlot>; optional?: Record<string, NodeSlot>; hidden?: Record<string, NodeSlot>; }; type NodeSlot = [string, NodeOptions] | [string]; type NodeOptions = Record<string, any>; export interface ObjectInfo { [k: string]: NodeConfig; } export type ApiError = { type: string; message: string; details: string; extra_info?: { input_name?: string; }; }; export type NodeError = { errors: ApiError[]; class_type: string; dependent_outputs: any[]; }; export type QueuePromptSuccess = { prompt_id: string; exec_info?: { queue_remaining?: number; }; }; export type QueuePromptError = { error: string | NodeError; node_errors: Record<string, NodeError>; }; export type QueuePrompt = QueuePromptSuccess | QueuePromptError; export {}; } type WorkflowOutput<D = unknown> = { images: ({ type: "buff"; data: ArrayBuffer; mime: string; } | { type: "url"; data: string; })[]; prompt_id: string; /** * Allows for a custom resolver to be provided. * * The custom resolver can parse non-image data into the `data` property, supporting generics. * * Related: https://github.com/StableCanvas/comfyui-client/issues/10 */ data?: D; }; interface IWorkflow { prompt: Record<string, WorkflowPromptNode>; workflow?: { nodes: []; links: []; groups: []; config: {}; extra: {}; version: 0.4; }; } type WorkflowPromptNode = { class_type: string; inputs: Record<string, any>; }; /** * The Client class provides a high-level interface for interacting with the ComfyUI API. * * @extends WsClient * * @example * ```typescript * const client = new Client({ * api_host: "YOUR_API_HOST", * clientId: "YOUR_CLIENT_ID", * }); * * const extensions = await client.getEmbeddings(); * console.log(extensions); * ``` */ declare class Client extends WsClient { private _plugins; constructor(config: Omit<IComfyApiConfig, "fetch" | "WebSocket"> & { fetch?: any; WebSocket?: any; }); /** * Use a plugin by calling its install method on this instance. * * @param {Plugin} plugin - The plugin to install. */ use(plugin: Plugin): void; /** * Gets a list of extension urls * @returns An array of script urls to import */ getExtensions(): Promise<string[]>; /** * Gets a list of embedding names * @returns An array of script urls to import */ getEmbeddings(): Promise<string[]>; /** * Loads node object definitions for the graph * @returns {Promise<ComfyUIClientResponseTypes.ObjectInfo>} The object info for the graph */ getNodeDefs(): Promise<ComfyUIClientResponseTypes.ObjectInfo>; /** * * @param {number} queue_index The index at which to queue the prompt, passing -1 will insert the prompt at the front of the queue * @param {Object} options * @param {Object} options.prompt The prompt to queue * @param {Object} options.workflow This png info to be added to resulting image * @returns {Promise<ComfyUIClientResponseTypes.QueuePrompt>} The response from the server */ queuePrompt(queue_index: number, { prompt, workflow }: { prompt: any; workflow: any; }): Promise<ComfyUIClientResponseTypes.QueuePrompt>; /** * Loads a list of items (queue or history) * @param {"queue" | "history"} type The type of items to load, queue or history * @returns The items of the specified type grouped by their status */ getItems(type: "history"): ReturnType<Client["getHistory"]>; getItems(type: "queue"): ReturnType<Client["getQueue"]>; /** * Gets the current state of the queue * @returns The currently running and queued items */ getQueue(): Promise<{ Running: Array<PromptBody>; Pending: Array<PromptBody>; }>; /** * Gets the prompt execution history * @returns Prompt history including node outputs */ getHistory(max_items?: number, options?: { offset?: number; }): Promise<{ History: Array<PromptQueueItem>; }>; /** * Gets system & device stats * @returns {ComfyUIClientResponseTypes.SystemStatsRoot} System stats such as python version, OS, per device info */ getSystemStats(): Promise<ComfyUIClientResponseTypes.SystemStatsRoot>; /** * Sends a POST request to the API * @param {string} type The endpoint to post to * @param {any} body Optional POST data */ private postApi; /** * Deletes an item from the specified list * @param {"queue" | "history"} type The type of item to delete, queue or history * @param {any} id The id of the item to delete */ deleteItem(type: "queue" | "history", id: any): Promise<void>; /** * Clears the specified list * @param {"queue" | "history"} type The type of list to clear, queue or history */ clearItems(type: "queue" | "history"): Promise<void>; /** * Interrupts the execution of the running prompt. If runningPromptId is provided, * it is included in the payload as a helpful hint to the backend. * @param {string | null} [runningPromptId] Optional Running Prompt ID to interrupt */ interrupt(runningPromptId?: string | null): Promise<void>; /** * Free up memory by unloading models and freeing memory */ free(params?: { unload_models?: boolean; free_memory?: boolean; }): Promise<void>; /** * Gets user configuration data and where data should be stored * @returns { Promise<{ storage: "server" | "browser", users?: Promise<string, unknown>, migrated?: boolean }> } */ getUserConfig(): Promise<any>; /** * Creates a new user * @param { string } username * @returns The fetch response */ createUser(username: string): Promise<Response>; /** * Gets all setting values for the current user * @returns { Promise<string, unknown> } A dictionary of id -> value */ getSettings(): Promise<Record<string, unknown>>; /** * Gets a setting for the current user * @param { string } id The id of the setting to fetch * @returns { Promise<unknown> } The setting value */ getSetting(id: string): Promise<unknown>; /** * Stores a dictionary of settings for the current user * @param { Record<string, unknown> } settings Dictionary of setting id -> value to save * @returns { Promise<void> } */ storeSettings(settings: Record<string, unknown>): Promise<Response>; /** * Stores a setting for the current user * @param { string } id The id of the setting to update * @param { unknown } value The value of the setting * @returns { Promise<void> } */ storeSetting(id: string, value: unknown): Promise<Response>; /** * Gets a user data file for the current user * @param { string } file The name of the userdata file to load * @param { RequestInit } [options] * @returns { Promise<unknown> } The fetch response object */ getUserData(file: string, options?: RequestInit): Promise<Response>; /** * Stores a user data file for the current user * @param { string } file The name of the userdata file to save * @param { any } data The data to save to the file * @param { RequestInit & { stringify?: boolean, throwOnError?: boolean } } [options] * @returns { Promise<void> } */ storeUserData(file: string, data: any, options?: RequestInit & { stringify?: boolean; throwOnError?: boolean; }): Promise<void>; /** * Gets a list of model folder keys (eg ['checkpoints', 'loras', ...]) * @returns The list of model folder keys */ getModelFolders(): Promise<ModelFolderInfo[]>; /** * Gets a list of models in the specified folder * @param {string} folder The folder to list models from, such as 'checkpoints' * @returns The list of model filenames within the specified folder */ getModels(folder: string): Promise<ModelFile[]>; /** * Gets the metadata for a model * @param {string} folder The folder containing the model * @param {string} model The model to get metadata for * @returns The metadata for the model */ viewMetadata(folder: string, model: string): Promise<any>; getLogs(): Promise<string>; getRawLogs(): Promise<LogsRawResponse>; /** * Retrieves the list of samplers from the node definitions. * * @return {Promise<string[]>} A promise that resolves to an array of strings representing the sampler names. */ getSamplers(): Promise<string[]>; /** * Retrieves the list of schedulers from the node definitions. * * @return {Promise<string[]>} A promise that resolves to an array of strings representing the scheduler names. */ getSchedulers(): Promise<string[]>; /** * Retrieves the list of model names from the node definitions. * * @return {Promise<string[]>} A promise that resolves to an array of strings representing the model names. */ getSDModels(): Promise<string[]>; /** * Retrieves the list of model names from the node definitions. * * @return {Promise<string[]>} A promise that resolves to an array of strings representing the model names. */ getCNetModels(): Promise<string[]>; /** * Retrieves the list of model names from the node definitions for the UpscaleModelLoader node. * * @return {Promise<string[]>} A promise that resolves to an array of strings representing the model names. */ getUpscaleModels(): Promise<string[]>; /** * Retrieves the list of hypernetwork names from the node definitions. * * @return {Promise<string[]>} A promise that resolves to an array of strings representing the hypernetwork names. */ getHyperNetworks(): Promise<string[]>; /** * Retrieves the list of LoRAs from the node definitions. * * @return {Promise<string[]>} A promise that resolves to an array of strings representing the LoRAs. */ getLoRAs(): Promise<string[]>; /** * Retrieves the list of VAE names from the node definitions. * * @return {Promise<string[]>} A promise that resolves to an array of strings representing the VAE names. */ getVAEs(): Promise<string[]>; /** * Retrieves the status of a prompt based on the provided prompt ID. * * @param {string} prompt_id - The ID of the prompt to check status for. * @return {Object} Object containing the running, pending, and done status of the prompt. */ getPromptStatus(prompt_id: string): Promise<{ running: boolean; pending: boolean; done: boolean; }>; /** * Retrieves the outputs of a prompt with the given ID from the history. * * @param {string} prompt_id - The ID of the prompt to retrieve the outputs for. * @return {Promise<Record<string, any>>} A promise that resolves to the outputs of the prompt. * @throws {Error} If the prompt with the given ID is not found in the history or if it failed with a non-"success" status. */ getPromptOutputs(prompt_id: string): Promise<Record<string, any>>; /** * Retrieves the result of a prompt with the given ID, resolved using the provided resolver. * * @param {string} prompt_id - The ID of the prompt to retrieve the result for. * @param {WorkflowOutputResolver<T>} resolver - The resolver to use when resolving the prompt result. * @return {Promise<WorkflowOutput<T>>} A promise that resolves to the result of the prompt. */ getPromptResult<T>(prompt_id: string, resolver: WorkflowOutputResolver<T>): Promise<WorkflowOutput<T>>; getPromptResult(prompt_id: string): Promise<WorkflowOutput>; /** * Asynchronously waits for the prompt with the provided ID to be done. * * @param {string} prompt_id - The ID of the prompt to wait for. * @param {number} [polling_ms=1000] - The number of milliseconds to wait between checks. * @param {number} [timeout_ms=5 * 60 * 1000] - The maximum number of milliseconds to wait. defaults to 5 minutes. must be greater than 1000ms. * @return {void} */ waitForPrompt(prompt_id: string, polling_ms?: number, timeout_ms?: number): Promise<void>; /** * Asynchronously waits for the prompt with the provided ID to be done, * using a WebSocket connection to receive updates. * * @param {string} prompt_id - The ID of the prompt to wait for. * @param {WorkflowOutputResolver<T>} resolver - A function to resolve the output of the prompt. * @param {number} [timeout_ms=5 * 60 * 1000] - The maximum number of milliseconds to wait. defaults to 5 minutes. must be greater than 1000ms. * @return {Promise<WorkflowOutput<T>>} A promise that resolves with the output of the prompt. */ waitForPromptWebSocket<T>(prompt_id: string, resolver: WorkflowOutputResolver<T>, timeout_ms?: number): Promise<WorkflowOutput<T>>; /** * Asynchronously enqueues a prompt with optional workflow and random seed. * * @param {Record<string, unknown>} prompt - The prompt to enqueue. * @param {Object} [options] - The options for enqueueing the prompt. * @param {Record<string, unknown>} [options.workflow] - The workflow for the prompt. * @return {Promise<ComfyUIClientResponseTypes.QueuePromptSuccess>} A promise that resolves with the enqueued prompt response. * @throws {Error} If there is an error in the response. */ _enqueue_prompt(prompt: Record<string, unknown>, options?: { workflow?: Record<string, unknown>; }): Promise<ComfyUIClientResponseTypes.QueuePromptSuccess>; /** * Asynchronously runs a prompt with the provided options. * * This function does not use WebSocket, but uses polling to get the result * So if your workflow contains custom ws events, this function will not be able to get these events * * @param {Record<string, unknown>} prompt - The prompt to run. * @param {Object} options - The options for running the prompt. * @param {Record<string, unknown>} options.workflow - The workflow for the prompt, It will be added to the png info of the generated image. * @param {number} [options.polling_ms=1000] - The number of milliseconds to polling query prompt result. * @param {number} [options.timeout_ms=5 * 60 * 1000] - The number of milliseconds to wait for the prompt result. must be greater than 1000. * @return {Promise<WorkflowOutput>} A promise that resolves with the prompt result. * * @deprecated Use `enqueue_polling` instead */ runPrompt(prompt: Record<string, unknown>, options?: { workflow?: Record<string, unknown>; polling_ms?: number; timeout_ms?: number; }): Promise<WorkflowOutput<WorkflowOutput>>; /** * Asynchronously enqueues a prompt and waits for the corresponding prompt websocket. * * This function does not use WebSocket, but uses polling to get the result * So if your workflow contains custom ws events, this function will not be able to get these events * * @param {Record<string, unknown>} prompt - The prompt to enqueue. * @param {EnqueueOptions<T>} [options] - The options for enqueueing the prompt. * @return {Promise<WorkflowOutput<T>>} A promise that resolves with the prompt result. */ enqueue_polling<T>(prompt: Record<string, unknown>, options?: EnqueueOptions<T>): Promise<WorkflowOutput<T>>; enqueue_polling(prompt: Record<string, unknown>, options?: EnqueueOptions): Promise<WorkflowOutput>; /** * Enqueues a prompt and waits for the corresponding prompt websocket. * * @param {Record<string, unknown>} prompt - The prompt to enqueue. * @param {EnqueueOptions<T>} [options] - The options for enqueueing the prompt. * @return {Promise<WorkflowOutput>} A promise that resolves with the prompt result. */ enqueue<T>(prompt: Record<string, unknown>, options?: EnqueueOptions<T>): Promise<WorkflowOutput<T>>; enqueue(prompt: Record<string, unknown>, options?: EnqueueOptions): Promise<WorkflowOutput>; /** * Listens for progress updates for a specific task. * * @param {EnqueueOptions["progress"]} fn - The progress callback function. * @param {string} task_id - The ID of the task to listen for progress updates. * @return {Function} A function that can be used to remove the progress listener. */ on_progress(fn: EnqueueOptions["progress"], task_id: string): () => void; } type WorkflowOutputResolver<T = unknown> = (acc: WorkflowOutput<T>, output: Record<string, unknown>, ctx: { client: Client; prompt_id: string; node_id: string; }) => WorkflowOutput<T>; type EnqueueOptions<T = unknown> = { /** * this data for PNG info */ workflow?: Record<string, unknown>; disable_random_seed?: boolean; progress?: (p: ComfyUiWsTypes.Messages.Progress) => void; on_error?: (err: Error) => void; resolver?: WorkflowOutputResolver<T>; polling_ms?: number; timeout_ms?: number; }; interface IComfyApiConfig { /** * The host address of the API server, defaults to '127.0.0.1:8188'. * @type {string} [api_host="127.0.0.1:8188"] */ api_host?: string; /** * The base path for the API endpoints, default is an empty string. * @type {string} [api_base=""] */ api_base?: string; /** * The client identification string, default is an empty string. * @type {string} [clientId=""] */ clientId?: string; /** * The name of the session, used for identifying the session instance, default is an empty string. * @type {string} [sessionName=""] */ sessionName?: string; /** * The username for authentication, default is 'sc-comfy-ui-client'. * @type {string} [user="""] */ user?: string; /** * Whether to use SSL for the connections, defaults to false. * @type {boolean} [ssl=false] */ ssl?: boolean; /** * These settings are for compatibility with Node.js environments. * @type {typeof WebSocket} [WebSocket] - The WebSocket class to use. */ WebSocket?: typeof WebSocket; /** * These settings are for compatibility with Node.js environments. * @type {typeof fetch} [fetch] - The fetch function to use. */ fetch?: typeof fetch; } type PromptMessage = [ event_name: string, body: { prompt_id: number; timestamp: number; } ]; type PromptBody = [ index: number, id: string, workflow: object, payload: { client_id: string; create_time: number; extra_pnginfo: { workflow: Record<string, unknown>; [key: string]: any; }; }, outputs: string[] ]; interface PromptQueueItem { prompt: PromptBody; outputs: Record<string, any>; status?: { status_str: "success" | "error"; completed: boolean; messages: PromptMessage[]; }; meta?: Record<string, any>; } interface PromptQueueHistory { [prompt_id: string]: PromptQueueItem; } interface ModelFolderInfo { name: string; folders: string[]; } interface ModelFile { name: string; pathIndex: number; } interface TerminalSize { cols: number; row: number; } interface LogEntry { t: string; m: string; } interface LogsRawResponse { size: TerminalSize; entries: LogEntry[]; } /** * A client for interacting with the ComfyUI API server using WebSockets. * * NOTE: CORS policy: Request header field comfy-user is not allowed by Access-Control-Allow-Headers in preflight response. Please config.use empty string in browser. * * @example * ```typescript * const client = new WsClient({ * api_host: "YOUR_API_HOST" * }); * * // Connect to the server * client.connect(); * * // Listen for status updates * client.on("status", (status) => { * console.log("Status:", status); * }); * * // when done, close the client * client.close(); */ declare class WsClient { static DEFAULT_API_HOST: string; static DEFAULT_API_BASE: string; static DEFAULT_USER: string; static IS_BROWSER: boolean; static readBinaryData(buf: ArrayBuffer): readonly [{ readonly type: "progress_text"; readonly data: { readonly nodeId: string; readonly text: string; }; }] | readonly [{ readonly type: "b_preview"; readonly data: Blob; }] | readonly [{ readonly type: "b_preview_with_metadata"; readonly data: { readonly blob: Blob; readonly nodeId: any; readonly displayNodeId: any; readonly parentNodeId: any; readonly realNodeId: any; readonly promptId: any; }; }, { readonly type: "b_preview"; readonly data: Blob; }]; api_host: string; api_base: string; clientId?: string; socket?: WebSocket | null; WebSocket: typeof WebSocket; ssl: boolean; user: string; fetch: typeof fetch; events: EventEmitter<ComfyUIClientEvents & Record<string & {}, any>>; protected socket_callbacks: Record<string, any>; get registered(): ((string & {}) | keyof ComfyUIClientEvents)[]; constructor(config: IComfyApiConfig); /** * Returns the headers for the API request. * * @param {RequestInit} [options] - (Optional) Additional options for the request. * @return {HeadersInit} The headers for the API request. */ apiHeaders(options?: RequestInit): HeadersInit; /** * Generates the URL for the API endpoint based on the provided route. * * @param {string} route - The route for the API endpoint. * @return {string} The generated URL for the API endpoint. */ apiURL(route: string): string; internalURL(route: string): string; /** * Generates a URL for viewing a specific file with the given filename, subfolder, and type. * * @param {string} filename - The name of the file to view. * @param {string} subfolder - The subfolder where the file is located. * @param {string} type - The type of the file. * @return {string} The URL for viewing the file. */ viewURL(filename: string, subfolder: string, type: string): string; /** * Generates the WebSocket URL based on the current API host and SSL configuration. * * @return {string} The generated WebSocket URL. */ wsURL(): string; /** * Fetches API data based on the provided route and options. * * NOTE: CORS policy: Request header field comfy-user is not allowed by Access-Control-Allow-Headers in preflight response. Please use empty string in browser. * * @param {string} route - The route for the API request. * @param {RequestInit} [options] - (Optional) Additional options for the request. * @return {Promise<Response>} A promise that resolves to the API response. */ fetchApi(route: string, options?: RequestInit): Promise<Response>; /** * Adds an event listener for the specified event type. * * @param {keyof ComfyUIClientEvents | (string & {})} type - The type of event to listen for. * @param {(...args: any) => void} callback - The callback function to be executed when the event is triggered. * @param {any} options - (Optional) Additional options for the event listener. * @return {() => void} A function that removes the event listener when called. */ addEventListener<T extends EventEmitter.EventNames<ComfyUIClientEvents>>(type: T, callback: EventEmitter.EventListener<ComfyUIClientEvents, T>, options?: any): () => void; /** * Adds an event listener for the specified event type. * * @param {keyof ComfyUIClientEvents | (string & {})} type - The type of event to listen for. * @param {(...args: any) => void} callback - The callback function to be executed when the event is triggered. * @param {any} options - (Optional) Additional options for the event listener. * @return {() => void} A function that removes the event listener when called. */ on<T extends EventEmitter.EventNames<ComfyUIClientEvents>>(type: T, callback: EventEmitter.EventListener<ComfyUIClientEvents, T>, options?: any): () => void; /** * Adds an event listener for the specified event type. * * @param {keyof ComfyUIClientEvents | (string & {})} type - The type of event to listen for. * @param {(...args: any) => void} callback - The callback function to be executed when the event is triggered. * @param {any} options - (Optional) Additional options for the event listener. * @return {() => void} A function that removes the event listener when called. */ once<T extends EventEmitter.EventNames<ComfyUIClientEvents>>(type: T, callback: EventEmitter.EventListener<ComfyUIClientEvents, T>, options?: any): () => void; protected _polling_timer: any; protected _polling_interval: number; /** * Poll status for colab and other things that don't support websockets. */ private startPollingQueue; protected addSocketCallback<K extends keyof WebSocketEventMap>(socket: WebSocket, type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): () => void; /** * Removes all event listeners from the given WebSocket and clears the socket_callbacks object. */ protected removeSocketCallbacks(): void; /** * Creates and connects a WebSocket for realtime updates * @param {boolean} isReconnect If the socket is connection is a reconnect attempt */ private createSocket; /** * Initializes sockets and realtime updates * * @deprecated move to client.connect() */ init(): void; closed: boolean; /** * Closes the WebSocket connection and cleans up event listeners */ close(): void; /** * Connects to the WebSocket server by creating a new socket connection. * * @param {Object} options - The options for connecting to the server. * @param {Object} options.polling - The options for polling. * @param {boolean} options.polling.enabled - Whether polling is enabled. * @param {number} [options.polling.interval] - The interval for polling. * @param {Object} options.websocket - The options for the WebSocket connection. * @param {boolean} options.websocket.enabled - Whether the WebSocket connection is enabled. * @param {number} [options.timeout_ms] - The timeout for the connection in milliseconds. * @return {Promise<boolean>} - A promise that resolves to true if the connection was successful, false otherwise. */ connect({ polling, websocket, timeout_ms, }?: { polling?: { enabled: boolean; interval?: number; }; websocket?: { enabled: boolean; }; timeout_ms?: number; }): Promise<unknown>; /** * Disconnects the WebSocket connection and cleans up event listeners. */ disconnect(): void; /** * Disconnects the WebSocket connection and cleans up event listeners. * * @return {void} This function does not return anything. */ _disconnectSocket(): void; /** * Disconnects the polling timer and sets it to null. * * @return {void} */ _disconnectPolling(): void; } declare class Disposable { protected _disposed: boolean; protected _disposed_cbs: any[]; dispose(): void; _connect(cb: () => void): void; } declare class InvokedWorkflow<T = unknown> extends Disposable { readonly options: { workflow: IWorkflow; client: Client; resolver?: WorkflowOutputResolver<T>; progress?: (p: ComfyUiWsTypes.Messages.Progress) => void; on_error?: (e: Error) => void; }; protected _task_id?: string; protected _result: WorkflowOutput<T>; is_done: boolean; enqueued: boolean; workflow: IWorkflow; client: Client; resolver: WorkflowOutputResolver<T>; /** * 因为 comfyui 的 websocket events 顺序混乱,在 execution_success 立马结束也可能导致事件丢失 * * Because the order of comfyui's websocket events is chaotic, the execution_success event may end immediately, causing events to be lost */ delay_done_ms: number; /** * The current task is being executed via WebSocket; this flag is used to determine whether the current `image_data` originates from this task. */ is_current_ws_executing: boolean; constructor(options: { workflow: IWorkflow; client: Client; resolver?: WorkflowOutputResolver<T>; progress?: (p: ComfyUiWsTypes.Messages.Progress) => void; on_error?: (e: Error) => void; }); get is_disposed(): boolean; get task_id(): string | undefined; protected _enqueue_guard(): void; protected _task_id_guard(): string; protected _done_guard(): void; protected _ws_guard(): void; protected is_owner_event(...args: any[]): boolean; /** * Adds an event listener for the specified event type. */ on<T extends EventEmitter.EventNames<ComfyUIClientEvents>>(type: T, callback: EventEmitter.EventListener<ComfyUIClientEvents, T>, options?: any): () => void; /** * Adds an once event listener for the specified event type. */ once<T extends EventEmitter.EventNames<ComfyUIClientEvents>>(type: T, callback: EventEmitter.EventListener<ComfyUIClientEvents, T>, options?: any): () => void; /** * Initiates the workflow by enqueuing the prompt and setting up the task ID. * * @return {void} */ enqueue(): Promise<void>; protected hook_progress(): Promise<void>; protected hook_executing(): Promise<void>; protected hook_image_data(): Promise<void>; protected resolve_to_result(data: ComfyUiWsTypes.Messages.Executed): void; /** * Retrieves the execution status of the workflow. * * @return {Promise<status>} A promise that resolves with the execution status of the workflow. */ query(): Promise<{ running: boolean; pending: boolean; done: boolean; }>; /** * Interrupts the execution of the workflow if it is currently enqueued. * Throws an error if the workflow is not enqueued or if the execution status cannot be interrupted. * * @return {Promise<void>} A promise that resolves when the interrupt is successful or rejects with an error. * @throws {Error} If the workflow is not enqueued or if the execution status cannot be interrupted. */ interrupt(): Promise<void>; protected collect_result(): Promise<WorkflowOutput<T>>; protected when_interrupted(cb: (data: ComfyUiWsTypes.Messages.ExecutionInterrupted) => any): void; protected when_execution_error(cb: (data: ComfyUiWsTypes.Messages.ExecutionError) => any): void; /** * Listen for the start event of the workflow. * @param {Function} cb - The callback function that will be called when the workflow starts. * @return {Function} A function that can be used to remove the listener. */ on_start(cb: () => void): void; /** * Waits for the workflow to complete and returns the result. * * *This function does not rely on WebSocket Events, so it will lose events output by WebSocket node * * @param {Object} options - options for waiting * @param {number} [options.polling_ms=1000] - polling interval in milliseconds * @return {Promise} promise that resolves with the result of the workflow */ wait_polling({ polling_ms }?: { polling_ms?: number; }): Promise<WorkflowOutput>; /** * Waits for the workflow to complete and returns the result. * * @return {Promise<WorkflowOutput>} promise that resolves with the result of the workflow */ wait(): Promise<WorkflowOutput>; } declare namespace ComfyUINodeTypes { interface NodeTypes { KSampler?: KSampler; CheckpointLoaderSimple?: CheckpointLoaderSimple; CLIPTextEncode?: CLIPTextEncode; CLIPSetLastLayer?: CLIPSetLastLayer; VAEDecode?: VAEDecode; VAEEncode?: VAEEncode; VAEEncodeForInpaint?: VAEEncodeForInpaint; VAELoader?: VAELoader; EmptyLatentImage?: EmptyLatentImage; LatentUpscale?: LatentUpscale; LatentUpscaleBy?: LatentUpscaleBy; LatentFromBatch?: LatentFromBatch; RepeatLatentBatch?: RepeatLatentBatch; SaveImage?: SaveImage; PreviewImage?: PreviewImage; LoadImage?: LoadImage; LoadImageMask?: LoadImageMask; LoadImageOutput?: LoadImageOutput; ImageScale?: ImageScale; ImageScaleBy?: ImageScaleBy; ImageInvert?: ImageInvert; ImageBatch?: ImageBatch; ImagePadForOutpaint?: ImagePadForOutpaint; EmptyImage?: EmptyImage; ConditioningAverage?: ConditioningAverage; ConditioningCombine?: ConditioningCombine; ConditioningConcat?: ConditioningConcat; ConditioningSetArea?: ConditioningSetArea; ConditioningSetAreaPercentage?: ConditioningSetAreaPercentage; ConditioningSetAreaStrength?: ConditioningSetAreaStrength; ConditioningSetMask?: ConditioningSetMask; KSamplerAdvanced?: KSamplerAdvanced; SetLatentNoiseMask?: SetLatentNoiseMask; LatentComposite?: LatentComposite; LatentBlend?: LatentBlend; LatentRotate?: LatentRotate; LatentFlip?: LatentFlip; LatentCrop?: LatentCrop; LoraLoader?: LoraLoader; CLIPLoader?: CLIPLoader; UNETLoader?: UNETLoader; DualCLIPLoader?: DualCLIPLoader; CLIPVisionEncode?: CLIPVisionEncode; StyleModelApply?: StyleModelApply; unCLIPConditioning?: unCLIPConditioning; ControlNetApply?: ControlNetApply; ControlNetApplyAdvanced?: ControlNetApplyAdvanced; ControlNetLoader?: ControlNetLoader; DiffControlNetLoader?: DiffControlNetLoader; StyleModelLoader?: StyleModelLoader; CLIPVisionLoader?: CLIPVisionLoader; VAEDecodeTiled?: VAEDecodeTiled; VAEEncodeTiled?: VAEEncodeTiled; unCLIPCheckpointLoader?: unCLIPCheckpointLoader; GLIGENLoader?: GLIGENLoader; GLIGENTextBoxApply?: GLIGENTextBoxApply; InpaintModelConditioning?: InpaintModelConditioning; CheckpointLoader?: CheckpointLoader; DiffusersLoader?: DiffusersLoader; LoadLatent?: LoadLatent; SaveLatent?: SaveLatent; ConditioningZeroOut?: ConditioningZeroOut; ConditioningSetTimestepRange?: ConditioningSetTimestepRange; LoraLoaderModelOnly?: LoraLoaderModelOnly; LatentAdd?: LatentAdd; LatentSubtract?: LatentSubtract; LatentMultiply?: LatentMultiply; LatentInterpolate?: LatentInterpolate; LatentConcat?: LatentConcat; LatentCut?: LatentCut; LatentBatch?: LatentBatch; LatentBatchSeedBehavior?: LatentBatchSeedBehavior; LatentApplyOperation?: LatentApplyOperation; LatentApplyOperationCFG?: LatentApplyOperationCFG; LatentOperationTonemapReinhard?: LatentOperationTonemapReinhard; LatentOperationSharpen?: LatentOperationSharpen; HypernetworkLoader?: HypernetworkLoader; UpscaleModelLoader?: UpscaleModelLoader; ImageUpscaleWithModel?: ImageUpscaleWithModel; ImageBlend?: ImageBlend; ImageBlur?: ImageBlur; ImageQuantize?: ImageQuantize; ImageSharpen?: ImageSharpen; ImageScaleToTotalPixels?: ImageScaleToTotalPixels; LatentCompositeMasked?: LatentCompositeMasked; ImageCompositeMasked?: ImageCompositeMasked; MaskToImage?: MaskToImage; ImageToMask?: ImageToMask; ImageColorToMask?: ImageColorToMask; SolidMask?: SolidMask; InvertMask?: InvertMask; CropMask?: CropMask; MaskComposite?: MaskComposite; FeatherMask?: FeatherMask; GrowMask?: GrowMask; ThresholdMask?: ThresholdMask; MaskPreview?: MaskPreview; PorterDuffImageComposite?: PorterDuffImageComposite; SplitImageWithAlpha?: SplitImageWithAlpha; JoinImageWithAlpha?: JoinImageWithAlpha; RebatchLatents?: RebatchLatents; RebatchImages?: RebatchImages; ModelMergeSimple?: ModelMergeSimple; ModelMergeBlocks?: ModelMergeBlocks; ModelMergeSubtract?: ModelMergeSubtract; ModelMergeAdd?: ModelMergeAdd; CheckpointSave?: CheckpointSave; CLIPMergeSimple?: CLIPMergeSimple; CLIPMergeSubtract?: CLIPMergeSubtract; CLIPMergeAdd?: CLIPMergeAdd; CLIPSave?: CLIPSave; VAESave?: VAESave; ModelSave?: ModelSave; TomePatchModel?: TomePatchModel; CLIPTextEncodeSDXLRefiner?: CLIPTextEncodeSDXLRefiner; CLIPTextEncodeSDXL?: CLIPTextEncodeSDXL; Canny?: Canny; FreeU?: FreeU; FreeU_V2?: FreeU_V2; SamplerCustom?: SamplerCustom; BasicScheduler?: BasicScheduler; KarrasScheduler?: KarrasScheduler; ExponentialScheduler?: ExponentialScheduler; PolyexponentialScheduler?: PolyexponentialScheduler; LaplaceScheduler?: LaplaceScheduler; VPScheduler?: VPScheduler; BetaSamplingScheduler?: BetaSamplingScheduler; SDTurboScheduler?: SDTurboScheduler; KSamplerSelect?: KSamplerSelect; SamplerEulerAncestral?: SamplerEulerAncestral; SamplerEulerAncestralCFGPP?: SamplerEulerAncestralCFGPP; SamplerLMS?: SamplerLMS; SamplerDPMPP_3M_SDE?: SamplerDPMPP_3M_SDE; SamplerDPMPP_2M_SDE?: SamplerDPMPP_2M_SDE; SamplerDPMPP_SDE?: SamplerDPMPP_SDE; SamplerDPMPP_2S_Ancestral?: SamplerDPMPP_2S_Ancestral; SamplerDPMAdaptative?: SamplerDPMAdaptative; SamplerER_SDE?: SamplerER_SDE; SamplerSASolver?: SamplerSASolver; SplitSigmas?: SplitSigmas; SplitSigmasDenoise?: SplitSigmasDenoise; FlipSigmas?: FlipSigmas; SetFirstSigma?: SetFirstSigma; ExtendIntermediateSigmas?: ExtendIntermediateSigmas; SamplingPercentToSigma?: SamplingPercentToSigma; CFGGuider?: CFGGuider; DualCFGGuider?: DualCFGGuider; BasicGuider?: BasicGuider; RandomNoise?: RandomNoise; DisableNoise?: DisableNoise; AddNoise?: AddNoise; SamplerCustomAdvanced?: SamplerCustomAdvanced; HyperTile?: HyperTile; ModelSamplingDiscrete?: ModelSamplingDiscrete; ModelSamplingContinuousEDM?: ModelSamplingContinuousEDM; ModelSamplingContinuousV?: ModelSamplingContinuousV; ModelSamplingStableCascade?: ModelSamplingStableCascade; ModelSamplingSD3?: ModelSamplingSD3; ModelSamplingAuraFlow?: ModelSamplingAuraFlow; ModelSamplingFlux?: ModelSamplingFlux; RescaleCFG?: RescaleCFG; ModelComputeDtype?: ModelComputeDtype; PatchModelAddDownscale?: PatchModelAddDownscale; ImageOnlyCheckpointLoader?: ImageOnlyCheckpointLoader; SVD_img2vid_Conditioning?: SVD_img2vid_Conditioning; VideoLinearCFGGuidance?: VideoLinearCFGGuidance; VideoTriangleCFGGuidance?: VideoTriangleCFGGuidance; ImageOnlyCheckpointSave?: ImageOnlyCheckpointSave; ConditioningSetAreaPercentageVideo?: ConditioningSetAreaPercentageVideo; TrainLoraNode?: TrainLoraNode; SaveLoRANode?: SaveLoRANode; LoraModelLoader?: LoraModelLoader; LoadImageSetFromFolderNode?: LoadImageSetFromFolderNode; LoadImageTextSetFromFolderNode?: LoadImageTextSetFromFolderNode; LossGraphNode?: LossGraphNode; SelfAttentionGuidance?: SelfAttentionGuidance; PerpNeg?: PerpNeg; PerpNegGuider?: PerpNegGuider; StableZero123_Conditioning?: StableZero123_Conditioning; StableZero123_Conditioning_Batched?: StableZero123_Conditioning_Batched; SV3D_Conditioning?: SV3D_Conditioning; SD_4XUpscale_Conditioning?: SD_4XUpscale_Conditioning; PhotoMakerLoader?: PhotoMakerLoader; PhotoMakerEncode?: PhotoMakerEncode; CLIPTextEncodePixArtAlpha?: CLIPTextEncodePixArtAlpha; CLIPTextEncode