@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,280 lines (1,253 loc) • 369 kB
TypeScript
/**
* 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;
}
interface ExecutionInterrupted {
prompt_id: string;
node_id: string;
node_type: string;
executed: string[];
}
interface Executing {
node: string;
display_node: string;
prompt_id: string;
}
interface Progress {
value: number;
max: number;
prompt_id: string;
node: 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;
}
}
}
type ComfyUIClientEvents = {
status: [ComfyUiWsTypes.Messages.Status["status"] | null];
progress: [ComfyUiWsTypes.Messages.Progress];
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: [];
/**
* 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;
}
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 QueuePrompt = {
prompt_id: string;
number: number;
node_errors: any;
} | {
error: string;
node_errors: Record<string, {
class_type: string;
dependent_outputs: string[];
errors: Array<{
details: string;
extra_info: any;
message: string;
type: string;
}>;
}>;
};
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 _cached_fn;
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>;
/**
* Clears the node object definitions cache
*/
resetCache(): void;
/**
*
* @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<Record<string, unknown>>;
Pending: Array<Record<string, unknown>>;
}>;
/**
* Gets the prompt execution history
* @returns Prompt history including node outputs
*/
getHistory(max_items?: number): Promise<{
History: Array<{
prompt: [number, string, any, any, any];
outputs: Record<string, unknown>;
status: {
status_str: string;
completed: boolean;
messages: any[];
};
}>;
}>;
/**
* 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
*/
interrupt(): 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>;
/**
* 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<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, unknown>>;
/**
* 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.
* @return {void}
*/
waitForPrompt(prompt_id: string, polling_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.
* @return {Promise<WorkflowOutput<T>>} A promise that resolves with the output of the prompt.
*/
waitForPromptWebSocket<T>(prompt_id: string, resolver: WorkflowOutputResolver<T>): 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<{ prompt_id: string; number: number; node_errors: any; }>} 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<{
prompt_id: string;
number: number;
node_errors: any;
}>;
/**
* 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.
* @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;
}): 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 {{ workflow?: Record<string, unknown>; disable_random_seed?: boolean; }} [options] - The options for enqueueing the prompt.
* @param {Record<string, unknown>} [options.workflow] - This data for PNG info.
* @param {boolean} [options.disable_random_seed] - Whether to disable random seed.
* @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 CachedFnOptions = {
expire_time?: number;
enabled?: boolean;
};
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;
resolver?: WorkflowOutputResolver<T>;
polling_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;
cache?: CachedFnOptions;
}
/**
* 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 loadImageData(buf: ArrayBuffer): {
image: ArrayBuffer;
mime: any;
};
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;
/**
* 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;
};
protected task_id?: string;
protected _result: WorkflowOutput<T>;
is_done: boolean;
enqueued: boolean;
workflow: IWorkflow;
client: Client;
resolver: WorkflowOutputResolver<T>;
constructor(options: {
workflow: IWorkflow;
client: Client;
resolver?: WorkflowOutputResolver<T>;
progress?: (p: ComfyUiWsTypes.Messages.Progress) => void;
});
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_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;
/**
* 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;
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;
LatentBatch?: LatentBatch;
LatentBatchSeedBehavior?: LatentBatchSeedBehavior;
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;
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;
TomePatchModel?: TomePatchModel;
CLIPTextEncodeSDXLRefiner?: CLIPTextEncodeSDXLRefiner;
CLIPTextEncodeSDXL?: CLIPTextEncodeSDXL;
Canny?: Canny;
FreeU?: FreeU;
FreeU_V2?: FreeU_V2;
SamplerCustom?: SamplerCustom;
BasicScheduler?: BasicScheduler;
KarrasScheduler?: KarrasScheduler;
ExponentialScheduler?: ExponentialScheduler;
PolyexponentialScheduler?: PolyexponentialScheduler;
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;
SplitSigmas?: SplitSigmas;
SplitSigmasDenoise?: SplitSigmasDenoise;
FlipSigmas?: FlipSigmas;
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;
PatchModelAddDownscale?: PatchModelAddDownscale;
ImageCrop?: ImageCrop;
RepeatImageBatch?: RepeatImageBatch;
ImageFromBatch?: ImageFromBatch;
SaveAnimatedWEBP?: SaveAnimatedWEBP;
SaveAnimatedPNG?: SaveAnimatedPNG;
ImageOnlyCheckpointLoader?: ImageOnlyCheckpointLoader;
SVD_img2vid_Conditioning?: SVD_img2vid_Conditioning;
VideoLinearCFGGuidance?: VideoLinearCFGGuidance;
VideoTriangleCFGGuidance?: VideoTriangleCFGGuidance;
ImageOnlyCheckpointSave?: ImageOnlyCheckpointSave;
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;
CLIPTextEncodeControlnet?: CLIPTextEncodeControlnet;
Morphology?: Morphology;
StableCascade_EmptyLatentImage?: StableCascade_EmptyLatentImage;
StableCascade_StageB_Conditioning?: StableCascade_StageB_Conditioning;
StableCascade_StageC_VAEEncode?: StableCascade_StageC_VAEEncode;
StableCascade_SuperResolutionControlnet?: StableCascade_SuperResolutionControlnet;
DifferentialDiffusion?: DifferentialDiffusion;
InstructPixToPixConditioning?: InstructPixToPixConditioning;
ModelMergeSD1?: ModelMergeSD1;
ModelMergeSD2?: ModelMergeSD2;
ModelMergeSDXL?: ModelMergeSDXL;
ModelMergeSD3_2B?: ModelMergeSD3_2B;
ModelMergeFlux1?: ModelMergeFlux1;
PerturbedAttentionGuidance?: PerturbedAttentionGuidance;
AlignYourStepsScheduler?: AlignYourStepsScheduler;
UNetSelfAttentionMultiply?: UNetSelfAttentionMultiply;
UNetCrossAttentionMultiply?: UNetCrossAttentionMultiply;
CLIPAttentionMultiply?: CLIPAttentionMultiply;
UNetTemporalAttentionMultiply?: UNetTemporalAttentionMultiply;
SamplerLCMUpscale?: SamplerLCMUpscale;
SamplerEulerCFGpp?: SamplerEulerCFGpp;
WebcamCapture?: WebcamCapture;
EmptyLatentAudio?: EmptyLatentAudio;
VAEEncodeAudio?: VAEEncodeAudio;
VAEDecodeAudio?: VAEDecodeAudio;
SaveAudio?: SaveAudio;
LoadAudio?: LoadAudio;
PreviewAudio?: PreviewAudio;
TripleCLIPLoader?: TripleCLIPLoader;
EmptySD3LatentImage?: EmptySD3LatentImage;
CLIPTextEncodeSD3?: CLIPTextEncodeSD3;
ControlNetApplySD3?: ControlNetApplySD3;
GITSScheduler?: GITSScheduler;
SetUnionControlNetType?: SetUnionControlNetType;
CLIPTextEncodeHunyuanDiT?: CLIPTextEncodeHunyuanDiT;
CLIPTextEncodeFlux?: CLIPTextEncodeFlux;
FluxGuidance?: FluxGuidance;
TimestepKeyframe?: TimestepKeyframe;
LatentKeyframe?: LatentKeyframe;
LatentKeyframeGroup?: LatentKeyframeGroup;
LatentKeyframeBatchedGroup?: LatentKeyframeBatchedGroup;
LatentKeyframeTiming?: LatentKeyframeTiming;
ACN_AdvancedControlNetApply?: ACN_AdvancedControlNetApply;
ControlNetLoaderAdvanced?: ControlNetLoaderAdvanced;
DiffControlNetLoaderAdvanced?: DiffControlNetLoaderAdvanced;
ScaledSoftControlNetWeights?: ScaledSoftControlNetWeights;
ScaledSoftMaskedUniversalWeights?: ScaledSoftMaskedUniversalWeights;
SoftControlNetWeights?: SoftControlNetWeights;
CustomControlNetWeights?: CustomControlNetWeights;
SoftT2IAdapterWeights?: SoftT2IAdapterWeights;
CustomT2IAdapterWeights?: CustomT2IAdapterWeights;
ACN_DefaultUniversalWeights?: ACN_DefaultUniversalWeights;
ACN_SparseCtrlRGBPreprocessor?: ACN_SparseCtrlRGBPreprocessor;
ACN_SparseCtrlLoaderAdvanced?: ACN_SparseCtrlLoaderAdvanced;
ACN_SparseCtrlMergedLoaderAdvanced?: ACN_SparseCtrlMergedLoaderAdvanced;
ACN_SparseCtrlIndexMethodNode?: ACN_SparseCtrlIndexMethodNode;
ACN_SparseCtrlSpreadMethodNode?: ACN_SparseCtrlSpreadMethodNode;
ACN_ReferencePreprocessor?: ACN_ReferencePreprocessor;
ACN_ReferenceControlNet?: ACN_ReferenceControlNet;
ACN_ReferenceControlNetFinetune?: ACN_ReferenceControlNetFinetune;
LoadImagesFromDirectory?: LoadImagesFromDirectory;
ADE_AnimateDiffLoRALoader?: ADE_AnimateDiffLoRALoader;
ADE_AnimateDiffSamplingSettings?: ADE_AnimateDiffSamplingSettings;
ADE_AnimateDiffKeyframe?: ADE_AnimateDiffKeyframe;
ADE_MultivalDynamic?: ADE_MultivalDynamic;
ADE_MultivalScaledMask?: ADE_MultivalScaledMask;
ADE_StandardStaticContextOptions?: ADE_StandardStaticContextOptions;
ADE_StandardUniformContextOptions?: ADE_StandardUniformContextOptions;
ADE_LoopedUniformContextOptions?: ADE_LoopedUniformContextOptions;
ADE_ViewsOnlyContextOptions?: ADE_ViewsOnlyContextOptions;
ADE_BatchedContextOptions?: ADE_BatchedContextOptions;
ADE_AnimateDiffUniformContextOptions?: ADE_AnimateDiffUniformContextOptions;
ADE_StandardStaticViewOptions?: ADE_StandardStaticViewOptions;
ADE_StandardUniformViewOptions?: ADE_StandardUniformViewOptions;
ADE_LoopedUniformViewOptions?: ADE_LoopedUniformViewOptions;
ADE_IterationOptsDefault?: ADE_IterationOptsDefault;
ADE_IterationOptsFreeInit?: ADE_IterationOptsFreeInit;
ADE_RegisterLoraHook?: ADE_RegisterLoraHook;
ADE_RegisterLoraHookModelOnly?: ADE_RegisterLoraHookModelOnly;
ADE_RegisterModelAsLoraHook?: ADE_RegisterModelAsLoraHook;
ADE_RegisterModelAsLoraHookModelOnly?: ADE_RegisterModelAsLoraHookModelOnly;
ADE_CombineLoraHooks?: ADE_CombineLoraHooks;
ADE_CombineLoraHooksFour?: ADE_CombineLoraHooksFour;
ADE_CombineLoraHooksEight?: ADE_CombineLoraHooksEight;
ADE_SetLoraHookKeyframe?: ADE_SetLoraHookKeyframe;
ADE_AttachLoraHookToCLIP?: ADE_AttachLoraHookToCLIP;
ADE_LoraHookKeyframe?: ADE_LoraHookKeyframe;
ADE_LoraHookKeyframeInterpolation?: ADE_LoraHookKeyframeInterpolation;
ADE_LoraHookKeyframeFromStrengthList?: ADE_LoraHookKeyframeFromStrengthList;
ADE_AttachLoraHookToConditioning?: ADE_AttachLoraHookToConditioning;
ADE_PairedConditioningSetMask?: ADE_PairedConditioningSetMask;
ADE_ConditioningSetMask?: ADE_ConditioningSetMask;
ADE_PairedConditioningSetMaskAndCombine?: ADE_PairedConditioningSetMaskAndCombine;
ADE_ConditioningSetMaskAndCombine?: ADE_ConditioningSetMaskAndCombine;
ADE_PairedConditioningSetUnmaskedAndCombine?: ADE_PairedConditioningSetUnmaskedAndCombine;
ADE_ConditioningSetUnmaskedAndCombine?: ADE_ConditioningSetUnmaskedAndCombine;
ADE_TimestepsConditioning?: ADE_TimestepsConditioning;
ADE_NoiseLayerAdd?: ADE_NoiseLayerAdd;
ADE_NoiseLayerAddWeighted?: ADE_NoiseLayerAddWeighted;
ADE_NoiseLayerReplace?: ADE_NoiseLayerReplace;
ADE_AnimateDiffSettings?: ADE_AnimateDiffSettings;
ADE_AdjustPESweetspotStretch?: ADE_AdjustPESweetspotStretch;
ADE_AdjustPEFullStretch?: ADE_AdjustPEFullStretch;
ADE_AdjustPEManual?: ADE_AdjustPEManual;
ADE_AdjustWeightAllAdd?: ADE_AdjustWeightAllAdd;
ADE_AdjustWeightAllMult?: ADE_AdjustW