"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PluginPublishedWebhookSchema = exports.InstalledPluginRecordSchema = exports.UIManifestSchema = exports.SettingsGroupSchema = exports.SettingsFieldSchema = exports.FieldValidationSchema = exports.SettingsDataTypeEnum = exports.SettingsUITypeEnum = exports.NodeVisualConfigSchema = exports.NodeLabelsSchema = exports.NodeIconsSchema = exports.NodeIconSchema = exports.NodeStylingSchema = exports.NodePaddingSchema = exports.NodeSizeSchema = exports.OutputHandleSchema = exports.InputHandleSchema = exports.HandleDataTypeEnum = exports.EdgeTypeEnum = exports.HandlePositionEnum = exports.HandleViewTypeEnum = exports.NodeTypeEnum = exports.SCHEMA_VERSION = void 0;
exports.coerceLegacyPluginType = coerceLegacyPluginType;
exports.normalizeUiManifest = normalizeUiManifest;
exports.toPluginPublishedWebhook = toPluginPublishedWebhook;
const zod_1 = require("zod");
// Versioning for DTO schemas
exports.SCHEMA_VERSION = "1.0.0";
// Core enums re-declared here to decouple consumers from SDK churn
exports.NodeTypeEnum = zod_1.z.enum([
    "custom",
    "trainer",
    "evaluator",
    "model",
    "model_layer",
    "sequence",
    "dataset",
    "dataloader",
    "preprocessor",
    "postprocessor",
    "augmentation_stack",
    "optimizer",
    "loss_function",
    "metric",
    "scheduler",
    "regularizer",
    "function",
    "pipeline",
    "report",
]);
exports.HandleViewTypeEnum = zod_1.z.enum([
    "default",
    "verticalBox",
    "circle-lg",
    "diamond",
    "square",
    "triangle",
]);
exports.HandlePositionEnum = zod_1.z.enum([
    "top",
    "top-right",
    "right",
    "bottom-right",
    "bottom",
    "bottom-left",
    "left",
    "top-left",
]);
exports.EdgeTypeEnum = zod_1.z.enum([
    "default",
    "solid",
    "dotted",
    "dashed",
    "accent",
    "muted",
    "success",
    "warning",
    "error",
]);
exports.HandleDataTypeEnum = zod_1.z.enum([
    "any",
    "string",
    "number",
    "boolean",
    "object",
    "array",
    "code",
    // Node types for variable provider validation
    "dataset",
    "dataloader",
    "model",
    "model_layer",
    "sequence",
    "trainer",
    "evaluator",
    "preprocessor",
    "postprocessor",
    "augmentation_stack",
    "optimizer",
    "loss_function",
    "metric",
    "scheduler",
    "regularizer",
    "function",
    "pipeline",
    "report",
    "custom",
]);
// Handles
exports.InputHandleSchema = zod_1.z.object({
    id: zod_1.z.string(),
    position: exports.HandlePositionEnum,
    viewType: exports.HandleViewTypeEnum,
    required: zod_1.z.boolean().optional(),
    label: zod_1.z.string().optional(),
    edgeType: exports.EdgeTypeEnum.optional(),
    dataType: exports.HandleDataTypeEnum,
    description: zod_1.z.string().optional(),
    // Tensor shape expected at this input (client-side evaluated)
    // Keep schema permissive to avoid breaking older manifests
    expectedShape: zod_1.z.any().optional(),
    validation: zod_1.z
        .object({
        minLength: zod_1.z.number().optional(),
        maxLength: zod_1.z.number().optional(),
        pattern: zod_1.z.string().optional(),
        customValidator: zod_1.z.string().optional(),
    })
        .optional(),
});
exports.OutputHandleSchema = zod_1.z.object({
    id: zod_1.z.string(),
    position: exports.HandlePositionEnum,
    viewType: exports.HandleViewTypeEnum,
    label: zod_1.z.string().optional(),
    edgeType: exports.EdgeTypeEnum.optional(),
    dataType: exports.HandleDataTypeEnum,
    description: zod_1.z.string().optional(),
});
// Visual
exports.NodeSizeSchema = zod_1.z.object({
    width: zod_1.z.number(),
    height: zod_1.z.number(),
    minWidth: zod_1.z.number().optional(),
    minHeight: zod_1.z.number().optional(),
    maxWidth: zod_1.z.number().optional(),
    maxHeight: zod_1.z.number().optional(),
    aspectRatio: zod_1.z.enum(["fixed", "flexible"]).optional(),
});
exports.NodePaddingSchema = zod_1.z.object({
    inner: zod_1.z.number().default(16),
    outer: zod_1.z.number().default(8),
    extraPadding: zod_1.z.boolean().default(false),
});
exports.NodeStylingSchema = zod_1.z.object({
    borderRadius: zod_1.z.number().default(8),
    borderWidth: zod_1.z.number().default(2),
    borderColor: zod_1.z.string().optional(),
    backgroundColor: zod_1.z.string().optional(),
    shadowLevel: zod_1.z
        .union([zod_1.z.literal(0), zod_1.z.literal(1), zod_1.z.literal(2), zod_1.z.literal(3)])
        .default(1),
    theme: zod_1.z.enum(["light", "dark", "auto"]).default("auto"),
});
exports.NodeIconSchema = zod_1.z.object({
    type: zod_1.z.enum(["svg", "fontawesome", "lucide"]).default("lucide"),
    value: zod_1.z.string(),
    position: zod_1.z.enum(["center", "top", "left", "bottom", "right"]).optional(),
});
exports.NodeIconsSchema = zod_1.z.object({
    primary: exports.NodeIconSchema.nullable().optional(),
    secondary: zod_1.z.array(exports.NodeIconSchema).default([]),
    showIconBackground: zod_1.z.boolean().default(true),
    iconSize: zod_1.z.enum(["small", "medium", "large"]).default("medium"),
});
exports.NodeLabelsSchema = zod_1.z.object({
    title: zod_1.z.string().optional(),
    titleDescription: zod_1.z.string().optional(),
    dynamicLabelTemplate: zod_1.z.string().optional(),
    showLabels: zod_1.z.boolean().default(true),
    labelPosition: zod_1.z.enum(["top", "bottom", "overlay"]).default("top"),
});
exports.NodeVisualConfigSchema = zod_1.z.object({
    containerType: zod_1.z
        .enum(["default", "box", "circle", "left-round"])
        .default("default"),
    size: exports.NodeSizeSchema,
    padding: exports.NodePaddingSchema.default({
        inner: 16,
        outer: 8,
        extraPadding: false,
    }),
    styling: exports.NodeStylingSchema.default({
        borderRadius: 8,
        borderWidth: 2,
        shadowLevel: 1,
        theme: "auto",
    }),
    icons: exports.NodeIconsSchema.default({
        secondary: [],
        showIconBackground: true,
        iconSize: "medium",
    }),
    labels: exports.NodeLabelsSchema.default({ showLabels: true, labelPosition: "top" }),
    sequence: zod_1.z
        .object({
        allowedItemType: zod_1.z.string().optional(),
        showItems: zod_1.z.boolean().default(true).optional(),
    })
        .optional(),
});
// Settings
exports.SettingsUITypeEnum = zod_1.z.enum([
    "input-text",
    "textarea",
    "input-number",
    "slider",
    "toggle",
    "checkbox",
    "dropdown",
    "radio",
    "multi-select",
    "code-editor",
    "file-upload",
    "color-picker",
    "date-picker",
]);
exports.SettingsDataTypeEnum = zod_1.z.enum([
    "string",
    "number",
    "boolean",
    "array",
    "object",
    "file",
    "date",
    "color",
]);
exports.FieldValidationSchema = zod_1.z.object({
    minLength: zod_1.z.number().optional(),
    maxLength: zod_1.z.number().optional(),
    min: zod_1.z.number().optional(),
    max: zod_1.z.number().optional(),
    pattern: zod_1.z.string().optional(),
    customValidator: zod_1.z.string().optional(),
    errorMessage: zod_1.z.string().optional(),
});
exports.SettingsFieldSchema = zod_1.z.object({
    key: zod_1.z.string(),
    label: zod_1.z.string(),
    type: exports.SettingsUITypeEnum,
    dataType: exports.SettingsDataTypeEnum,
    defaultValue: zod_1.z.any().optional(),
    required: zod_1.z.boolean(),
    description: zod_1.z.string().optional(),
    validation: exports.FieldValidationSchema.optional(),
    options: zod_1.z
        .array(zod_1.z.object({
        label: zod_1.z.string(),
        value: zod_1.z.any(),
        description: zod_1.z.string().optional(),
        disabled: zod_1.z.boolean().optional(),
    }))
        .optional(),
    placeholder: zod_1.z.string().optional(),
    group: zod_1.z.string().optional(),
    order: zod_1.z.number().optional(),
    conditionalDisplay: zod_1.z
        .object({
        dependsOn: zod_1.z.string(),
        condition: zod_1.z.enum([
            "equals",
            "not-equals",
            "greater-than",
            "less-than",
            "contains",
            "not-contains",
        ]),
        value: zod_1.z.any(),
    })
        .optional(),
});
exports.SettingsGroupSchema = zod_1.z.object({
    id: zod_1.z.string(),
    label: zod_1.z.string(),
    description: zod_1.z.string().optional(),
    collapsible: zod_1.z.boolean().default(true),
    defaultExpanded: zod_1.z.boolean().default(true),
    fields: zod_1.z.array(zod_1.z.string()),
    order: zod_1.z.number().optional(),
});
// UI Manifest DTO (what UI consumes)
exports.UIManifestSchema = zod_1.z.object({
    schemaVersion: zod_1.z.string().default(exports.SCHEMA_VERSION),
    name: zod_1.z.string(),
    version: zod_1.z.string(),
    description: zod_1.z.string().optional(),
    author: zod_1.z.string().optional(),
    main: zod_1.z.string().default("dist/index.js"),
    entrypointClassName: zod_1.z.string(),
    keywords: zod_1.z.array(zod_1.z.string()).default([]),
    repository: zod_1.z.object({ type: zod_1.z.string(), url: zod_1.z.string().url() }).optional(),
    pluginType: exports.NodeTypeEnum, // required
    tensorify: zod_1.z
        .object({ pluginType: zod_1.z.string().optional() })
        .partial()
        .optional(),
    frontendConfigs: zod_1.z.object({
        id: zod_1.z.string(),
        name: zod_1.z.string(),
        category: exports.NodeTypeEnum,
        nodeType: exports.NodeTypeEnum,
        visual: exports.NodeVisualConfigSchema,
        inputHandles: zod_1.z.array(exports.InputHandleSchema),
        outputHandles: zod_1.z.array(exports.OutputHandleSchema),
        settingsFields: zod_1.z.array(exports.SettingsFieldSchema),
        settingsGroups: zod_1.z.array(exports.SettingsGroupSchema).optional(),
    }),
    capabilities: zod_1.z.array(zod_1.z.string()).default([]),
    requirements: zod_1.z
        .object({
        minSdkVersion: zod_1.z.string().optional(),
        dependencies: zod_1.z.array(zod_1.z.string()).default([]),
        pythonPackages: zod_1.z.array(zod_1.z.string()).optional(),
        nodePackages: zod_1.z.array(zod_1.z.string()).optional(),
        environmentVariables: zod_1.z.array(zod_1.z.string()).optional(),
    })
        .default({ dependencies: [] }),
    // Enforce emits presence and shape
    emits: zod_1.z
        .object({
        variables: zod_1.z
            .array(zod_1.z.object({
            value: zod_1.z.string().min(1),
            switchKey: zod_1.z.string().min(1),
            isOnByDefault: zod_1.z.boolean().optional(),
            type: zod_1.z.string().optional(),
            // Tensor shape description for this emitted variable
            // Use z.any() to preserve forward/backward compatibility
            shape: zod_1.z.any().optional(),
        }))
            .default([]),
        imports: zod_1.z
            .array(zod_1.z.object({
            path: zod_1.z.string().min(1),
            items: zod_1.z.array(zod_1.z.string()).optional(),
            alias: zod_1.z.string().optional(),
            as: zod_1.z.record(zod_1.z.string(), zod_1.z.string()).optional(),
        }))
            .default([]),
    })
        .default({ variables: [], imports: [] }),
});
// Installed plugin record (DB DTO shape – not Prisma types)
exports.InstalledPluginRecordSchema = zod_1.z.object({
    id: zod_1.z.string().uuid(),
    slug: zod_1.z.string(),
    description: zod_1.z.string().nullable(),
    pluginType: zod_1.z.string(),
    manifest: exports.UIManifestSchema.nullable(),
    createdAt: zod_1.z.string(),
    updatedAt: zod_1.z.string(),
});
// Webhook payload (backend -> plugins site)
exports.PluginPublishedWebhookSchema = zod_1.z.object({
    slug: zod_1.z.string(),
    name: zod_1.z.string(),
    version: zod_1.z.string().optional(),
    description: zod_1.z.string().optional(),
    author: zod_1.z.string(),
    authorFullName: zod_1.z.string().optional(),
    status: zod_1.z.string().optional(),
    isPublic: zod_1.z.boolean().optional(),
    githubUrl: zod_1.z.string().url().optional(),
    entrypointClassName: zod_1.z.string().optional(),
    files: zod_1.z.array(zod_1.z.string()),
    authorId: zod_1.z.string(),
    publishedAt: zod_1.z.string().optional(),
    readme: zod_1.z.string().optional(),
    tags: zod_1.z.string().optional(),
    sdkVersion: zod_1.z.string().optional(),
    pluginType: zod_1.z.string().optional(),
});
// Normalizers
function coerceLegacyPluginType(input) {
    if (typeof input !== "string")
        return undefined;
    const lower = input.toLowerCase();
    if (exports.NodeTypeEnum.options.includes(lower))
        return lower;
    // common aliases
    const map = {
        modelLayer: "model_layer",
    };
    return map[lower];
}
function normalizeUiManifest(manifest) {
    // Best-effort coercion for legacy keys
    const m = manifest || {};
    if (m.frontendConfigs?.nodeType && !m.frontendConfigs?.category) {
        m.frontendConfigs.category = m.frontendConfigs.nodeType;
    }
    // Resolve pluginType precedence:
    // 1) package.json tensorify-settings.pluginType if provided via caller as m.tensorifySettings?.pluginType
    // 2) legacy m.tensorify.pluginType
    // 3) existing m.pluginType
    const fromTensorifySettings = coerceLegacyPluginType(m.tensorifySettings?.pluginType);
    const fromLegacyTensorify = coerceLegacyPluginType(m.tensorify?.pluginType);
    m.pluginType = fromTensorifySettings || fromLegacyTensorify || m.pluginType;
    // V2-Alpha: prev/next handles are now optional
    // They were required for path-based V2-Beta navigation but not needed for graph-based V2-Alpha
    // Keeping the variable provider check for backward compatibility only
    // const isVariableProvider = ["dataset", "dataloader"].includes(m.pluginType);
    // Skip prev/next validation for V2-Alpha architecture
    // if (!isVariableProvider) {
    //   const inputHandles = m.frontendConfigs?.inputHandles || [];
    //   const outputHandles = m.frontendConfigs?.outputHandles || [];
    //   const hasPrev = inputHandles.some(
    //     (h: any) =>
    //       h.id === "prev" && h.position === "left" && h.required === true
    //   );
    //   const hasNext = outputHandles.some(
    //     (h: any) => h.id === "next" && h.position === "right"
    //   );
    //   if (!hasPrev) {
    //     throw new Error(
    //       "An input handle 'prev' on the LEFT marked required: true is required"
    //     );
    //   }
    //   if (!hasNext) {
    //     throw new Error("An output handle 'next' on the RIGHT is required");
    //   }
    // }
    const parsed = exports.UIManifestSchema.parse(m);
    // Validate that for each emitted variable switchKey, a corresponding settings field exists
    const settingsFields = parsed.frontendConfigs.settingsFields || [];
    const settingsMap = new Map();
    for (const f of settingsFields)
        settingsMap.set(f.key, f);
    for (const v of parsed.emits.variables) {
        const rawKey = v.switchKey.includes(".")
            ? v.switchKey.split(".").pop()
            : v.switchKey;
        const field = settingsMap.get(rawKey);
        if (!field) {
            throw new Error(`Emitted variable '${v.value}' requires a settings toggle '${rawKey}' as referenced by switchKey '${v.switchKey}'`);
        }
        if (field.type !== "toggle" ||
            field.dataType !== "boolean") {
            throw new Error(`Settings field '${rawKey}' must be TOGGLE/BOOLEAN because it controls emitted variable '${v.value}'`);
        }
        if (field.required !== true) {
            throw new Error(`Settings field '${rawKey}' must be required: true because it controls emitted variable '${v.value}'`);
        }
        if (typeof v.isOnByDefault === "boolean") {
            const defVal = field.defaultValue;
            if (defVal !== v.isOnByDefault) {
                throw new Error(`Settings field '${rawKey}'.defaultValue must match isOnByDefault (${String(v.isOnByDefault)}) for emitted variable '${v.value}'`);
            }
        }
    }
    return parsed;
}
function toPluginPublishedWebhook(input) {
    return exports.PluginPublishedWebhookSchema.parse(input);
}
//# sourceMappingURL=spec.js.map