import { z } from 'zod' import { zBaseInputOptions, zBooleanInputOptions, zComboInputOptions, zFloatInputOptions, zIntInputOptions, zStringInputOptions } from '@/schemas/nodeDefSchema' const zIntInputSpec = zIntInputOptions.extend({ type: z.literal('INT'), name: z.string(), isOptional: z.boolean().optional() }) const zFloatInputSpec = zFloatInputOptions.extend({ type: z.literal('FLOAT'), name: z.string(), isOptional: z.boolean().optional() }) const zBooleanInputSpec = zBooleanInputOptions.extend({ type: z.literal('BOOLEAN'), name: z.string(), isOptional: z.boolean().optional() }) const zStringInputSpec = zStringInputOptions.extend({ type: z.literal('STRING'), name: z.string(), isOptional: z.boolean().optional() }) const zComboInputSpec = zComboInputOptions.extend({ type: z.literal('COMBO'), name: z.string(), isOptional: z.boolean().optional() }) const zColorInputSpec = zBaseInputOptions.extend({ type: z.literal('COLOR'), name: z.string(), isOptional: z.boolean().optional(), options: z .object({ default: z.string().optional() }) .optional() }) const zImageInputSpec = zBaseInputOptions.extend({ type: z.literal('IMAGE'), name: z.string(), isOptional: z.boolean().optional(), options: z.record(z.unknown()).optional() }) const zImageCompareInputSpec = zBaseInputOptions.extend({ type: z.literal('IMAGECOMPARE'), name: z.string(), isOptional: z.boolean().optional(), options: z.record(z.unknown()).optional() }) const zBoundingBoxInputSpec = zBaseInputOptions.extend({ type: z.literal('BOUNDINGBOX'), name: z.string(), isOptional: z.boolean().optional(), component: z.enum(['ImageCrop']).optional(), default: z .object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() }) .optional() }) const zMarkdownInputSpec = zBaseInputOptions.extend({ type: z.literal('MARKDOWN'), name: z.string(), isOptional: z.boolean().optional(), options: z .object({ content: z.string().optional() }) .optional() }) const zChartInputSpec = zBaseInputOptions.extend({ type: z.literal('CHART'), name: z.string(), isOptional: z.boolean().optional(), options: z .object({ type: z.enum(['bar', 'line']).optional(), data: z.object({}).optional() }) .optional() }) const zGalleriaInputSpec = zBaseInputOptions.extend({ type: z.literal('GALLERIA'), name: z.string(), isOptional: z.boolean().optional(), options: z .object({ images: z.array(z.string()).optional() }) .optional() }) const zTextareaInputSpec = zBaseInputOptions.extend({ type: z.literal('TEXTAREA'), name: z.string(), isOptional: z.boolean().optional(), options: z .object({ rows: z.number().optional(), cols: z.number().optional(), default: z.string().optional() }) .optional() }) const zCustomInputSpec = zBaseInputOptions.extend({ type: z.string(), name: z.string(), isOptional: z.boolean().optional() }) const zInputSpec = z.union([ zIntInputSpec, zFloatInputSpec, zBooleanInputSpec, zStringInputSpec, zComboInputSpec, zColorInputSpec, zImageInputSpec, zImageCompareInputSpec, zBoundingBoxInputSpec, zMarkdownInputSpec, zChartInputSpec, zGalleriaInputSpec, zTextareaInputSpec, zCustomInputSpec ]) // Output specs const zOutputSpec = z.object({ index: z.number(), name: z.string(), type: z.string(), is_list: z.boolean(), options: z.array(z.any()).optional(), tooltip: z.string().optional() }) // Main node definition schema export const zComfyNodeDef = z.object({ inputs: z.record(zInputSpec), outputs: z.array(zOutputSpec), hidden: z.record(z.any()).optional(), name: z.string(), display_name: z.string(), description: z.string(), help: z.string().optional(), category: z.string(), output_node: z.boolean(), python_module: z.string(), deprecated: z.boolean().optional(), experimental: z.boolean().optional(), api_node: z.boolean().optional() }) // Export types type IntInputSpec = z.infer type FloatInputSpec = z.infer type BooleanInputSpec = z.infer type StringInputSpec = z.infer export type ComboInputSpec = z.infer export type ColorInputSpec = z.infer export type ImageCompareInputSpec = z.infer export type BoundingBoxInputSpec = z.infer export type ChartInputSpec = z.infer export type GalleriaInputSpec = z.infer export type TextareaInputSpec = z.infer export type CustomInputSpec = z.infer export type InputSpec = z.infer export type OutputSpec = z.infer export type ComfyNodeDef = z.infer export const isIntInputSpec = ( inputSpec: InputSpec ): inputSpec is IntInputSpec => { return inputSpec.type === 'INT' } export const isFloatInputSpec = ( inputSpec: InputSpec ): inputSpec is FloatInputSpec => { return inputSpec.type === 'FLOAT' } export const isBooleanInputSpec = ( inputSpec: InputSpec ): inputSpec is BooleanInputSpec => { return inputSpec.type === 'BOOLEAN' } export const isStringInputSpec = ( inputSpec: InputSpec ): inputSpec is StringInputSpec => { return inputSpec.type === 'STRING' } export const isComboInputSpec = ( inputSpec: InputSpec ): inputSpec is ComboInputSpec => { return inputSpec.type === 'COMBO' } export const isChartInputSpec = ( inputSpec: InputSpec ): inputSpec is ChartInputSpec => { return inputSpec.type === 'CHART' }