Files
immich/server/src/dtos/plugin-manifest.dto.ts
T
Alex 8682be4774 feat: workflow template (#28553)
* wip: confirm before existing and disable/enable save button condition

* fix: get correct workflow detail

* wip: add back workflow summary

* wip: add back json editor

* wip: step property badge

* wip: redesign card flow

* wip: redesign card flow

* redesign workflow summary

* wworkflow summary styling

* wip

* drag and drop

* list redesign

* refactor

* refactor

* remove deadcode

* refactor

* insert steps

* push down when dropped

* feat: workflow template

* simplify

* move template to manifest

* feat: hash manifest file

* fix: template column

* fix: migration

* fix: workflow lookup

* chore: clean up

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2026-05-26 16:47:05 -04:00

72 lines
3.1 KiB
TypeScript

import { createZodDto } from 'nestjs-zod';
import { JsonSchemaSchema } from 'src/dtos/json-schema.dto';
import { WorkflowTriggerSchema, WorkflowTypeSchema } from 'src/enum';
import z from 'zod';
const pluginNameRegex = /^[a-z0-9-]+[a-z0-9]$/;
const semverRegex =
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
export const PluginManifestMethodSchemaSchema = JsonSchemaSchema.nullable()
.optional()
.transform((value) => (value && Object.keys(value).length === 0 ? null : value));
const PluginManifestMethodSchema = z
.object({
name: z.string().min(1).describe('Method name'),
title: z.string().min(1).describe('Method title'),
description: z.string().min(1).describe('Method description'),
types: z.array(WorkflowTypeSchema).min(1).describe('Workflow type'),
hostFunctions: z.boolean().optional().default(false).describe('Method uses host functions'),
schema: PluginManifestMethodSchemaSchema.describe('Schema'),
uiHints: z.array(z.string()).optional().describe('Ui hints, for example "filter"'),
})
.meta({ id: 'PluginManifestMethodDto' });
const PluginManifestTemplateStepSchema = z
.object({
method: z.string().min(1).describe('Step plugin method (pluginName#methodName)'),
config: z.record(z.string(), z.unknown()).nullable().optional().describe('Step configuration'),
enabled: z.boolean().optional().describe('Whether the step is enabled'),
})
.meta({ id: 'PluginManifestTemplateStepDto' });
const PluginManifestTemplateSchema = z
.object({
name: z.string().min(1).describe('Template name (must be unique within the manifest)'),
title: z.string().min(1).describe('Template title'),
description: z.string().min(1).describe('Template description'),
trigger: WorkflowTriggerSchema.describe('Workflow trigger'),
steps: z.array(PluginManifestTemplateStepSchema).describe('Workflow steps'),
})
.meta({ id: 'PluginManifestTemplateDto' });
const PluginManifestSchema = z
.object({
name: z
.string()
.min(1)
.regex(
pluginNameRegex,
'Plugin name must contain only lowercase letters, numbers, and hyphens, and cannot end with a hyphen',
)
.describe('Plugin name (lowercase, numbers, hyphens only)'),
version: z.string().regex(semverRegex).describe('Plugin version (semver)'),
title: z.string().min(1).describe('Plugin title'),
description: z.string().min(1).describe('Plugin description'),
wasmPath: z.string().min(1).describe('WASM file path'),
author: z.string().min(1).describe('Plugin author'),
methods: z.array(PluginManifestMethodSchema).optional().default([]).describe('Plugin methods'),
templates: z
.array(PluginManifestTemplateSchema)
.optional()
.default([])
.refine((templates) => new Set(templates.map((t) => t.name)).size === templates.length, {
error: 'Template names must be unique within the manifest',
})
.describe('Workflow templates'),
})
.meta({ id: 'PluginManifestDto' });
export class PluginManifestDto extends createZodDto(PluginManifestSchema) {}