UNPKG

@tensorify.io/sdk

Version:

TypeScript SDK for developing Tensorify plugins with V2-Alpha definition/execution pattern and legacy compatibility

416 lines 15.2 kB
"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", "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", ]); // 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) 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, // V2-Alpha: Removed strict prev/next handle requirements inputHandles: zod_1.z.array(exports.InputHandleSchema), /* .refine( (arr) => arr.some( (h) => h.id === "prev" && h.position === "left" && h.required === true ), { message: "An input handle 'prev' on the LEFT marked required: true is required", } ), */ outputHandles: zod_1.z.array(exports.OutputHandleSchema), /* .refine( (arr) => arr.some((h) => h.id === "next" && h.position === "right"), { message: "An output handle 'next' on the RIGHT is required" } ), */ 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(), // Tensor shape description to power intellisense 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; 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