EmboFlow/apps/api/src/modules/plugins/builtin/delivery-nodes.ts

129 lines
3.9 KiB
TypeScript

import type { ExecutorType, NodeRuntimeConfig } from "../../../../worker/src/contracts/execution-context.ts";
export type DeliveryNodeDefinition = {
id: string;
name: string;
category: "Source" | "Transform" | "Inspect" | "Annotate" | "Export" | "Utility";
description: string;
defaultExecutorType?: ExecutorType;
defaultExecutorConfig?: Record<string, unknown>;
supportsCodeHook?: boolean;
allowsMultipleIncoming?: boolean;
};
const DEFAULT_DOCKER_EXECUTOR_CONFIG = {
image: "python:3.11-alpine",
networkMode: "none",
} as const;
function createDockerDefaults(): Pick<DeliveryNodeDefinition, "defaultExecutorType" | "defaultExecutorConfig"> {
return {
defaultExecutorType: "docker",
defaultExecutorConfig: { ...DEFAULT_DOCKER_EXECUTOR_CONFIG },
};
}
export const DELIVERY_NODE_DEFINITIONS: readonly DeliveryNodeDefinition[] = [
{
id: "source-asset",
name: "Source Asset",
category: "Source",
description: "Load the uploaded asset or registered path into the workflow.",
...createDockerDefaults(),
},
{
id: "extract-archive",
name: "Extract Archive",
category: "Transform",
description: "Unpack tar, zip, or zst archives for downstream processing.",
...createDockerDefaults(),
supportsCodeHook: true,
},
{
id: "rename-folder",
name: "Rename Delivery Folder",
category: "Transform",
description: "Rename the top-level folder to the delivery naming convention.",
...createDockerDefaults(),
supportsCodeHook: true,
},
{
id: "validate-structure",
name: "Validate Structure",
category: "Inspect",
description: "Check required directories and metadata files.",
...createDockerDefaults(),
supportsCodeHook: true,
},
{
id: "validate-metadata",
name: "Validate Metadata",
category: "Inspect",
description: "Validate meta.json, intrinsics.json, and video_meta.json.",
...createDockerDefaults(),
supportsCodeHook: true,
},
{
id: "union-assets",
name: "Union Assets",
category: "Utility",
description: "Merge multiple upstream asset sets into one deduplicated asset set.",
...createDockerDefaults(),
supportsCodeHook: true,
allowsMultipleIncoming: true,
},
{
id: "intersect-assets",
name: "Intersect Assets",
category: "Utility",
description: "Keep only the assets that exist in every upstream asset set.",
...createDockerDefaults(),
supportsCodeHook: true,
allowsMultipleIncoming: true,
},
{
id: "difference-assets",
name: "Difference Assets",
category: "Utility",
description: "Subtract downstream asset sets from the first upstream asset set.",
...createDockerDefaults(),
supportsCodeHook: true,
allowsMultipleIncoming: true,
},
{
id: "export-delivery-package",
name: "Export Delivery Package",
category: "Export",
description: "Publish the normalized package for downstream upload or handoff.",
...createDockerDefaults(),
},
] as const;
const DELIVERY_NODE_DEFINITION_BY_ID = new Map(
DELIVERY_NODE_DEFINITIONS.map((definition) => [definition.id, definition]),
);
export function getDeliveryNodeDefinition(definitionId: string) {
return DELIVERY_NODE_DEFINITION_BY_ID.get(definitionId);
}
export function buildDefaultNodeRuntimeConfig(definitionId: string): NodeRuntimeConfig | undefined {
const definition = getDeliveryNodeDefinition(definitionId);
if (!definition) {
return undefined;
}
const config: NodeRuntimeConfig = {};
if (definition.defaultExecutorType) {
config.executorType = definition.defaultExecutorType;
}
if (definition.defaultExecutorConfig) {
config.executorConfig = { ...definition.defaultExecutorConfig };
}
return Object.keys(config).length > 0 ? config : undefined;
}
export function deliveryNodeAllowsMultipleIncoming(definitionId: string) {
return Boolean(getDeliveryNodeDefinition(definitionId)?.allowsMultipleIncoming);
}