@tensorify.io/sdk
Version:
TypeScript SDK for developing Tensorify plugins with V2-Alpha definition/execution pattern and legacy compatibility
416 lines • 15.2 kB
JavaScript
"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