import {z} from 'zod' export type GetApiHubWorkflowsArgs = {collection_topic?: string | undefined, version?: ('draft' | 'published') | undefined}; export type GetApiHubWorkflowsOptions = {baseUrl?: string | undefined, bearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const triggerNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("trigger"), trigger_type: z.enum(["manual", "schedule", "webhook", "gateway", "embed", "email", "object-store", "record", "task", "email-delivery", "mail"]).optional(), payload: z.record(z.string(), z.unknown())}); export const agentNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("agent"), payload: z.object({agent: z.object({name: z.string(), llm_provider: z.enum(["claude", "anthropic"]), model: z.string(), description: z.string().optional(), behaviour: z.string().optional(), output_schema: z.record(z.string(), z.string()).optional(), has_tools: z.boolean().optional(), tools: z.array(z.string()).optional(), knowledge: z.array(z.string()).optional(), timeout: z.number().optional()}).optional(), subject: z.string().optional(), node_subject: z.string().optional(), prompt: z.union([z.string(), z.object({})]).optional(), await: z.boolean().optional(), knowledge: z.array(z.string()).optional()})}); export const nodeOptions = z.object({flat_map: z.boolean().optional(), backoff_ms: z.number().int().optional(), timeout: z.number().int().optional(), attempts: z.number().int().gte(1).lte(10).optional(), ignore_response_codes: z.array(z.number().int()).optional()}); export const functionNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("function"), subject: z.string(), payload: z.unknown(), response_map: z.unknown(), options: nodeOptions.optional()}); export const httpPayload = z.object({base_url: z.string().optional(), url: z.string(), method: z.string(), data: z.object({}).optional(), params: z.object({}).optional(), query: z.object({}).optional(), headers: z.record(z.string(), z.string()).optional(), timeout: z.number().int().optional()}); export const integrationNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("integration"), integration_id: z.string().optional(), request_type_id: z.string().optional(), oauth: z.string().optional(), payload: httpPayload, options: nodeOptions.optional()}); export const httpNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("http"), payload: httpPayload, options: nodeOptions.optional()}); export const flowNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("flow"), subject: z.string(), payload: z.unknown(), await: z.boolean().optional(), response_map: z.unknown(), options: nodeOptions.optional()}); export const evalNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("eval"), payload: z.object({code: z.string(), params: z.record(z.string(), z.unknown())}), options: nodeOptions.optional()}); export const conditionNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("condition"), payload: z.object({rules: z.array(z.object({if: z.string().optional(), then: z.array(z.string()).optional(), else: z.array(z.string()).optional()})).optional()})}); export const rulesNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("rules"), payload: z.object({rules: z.object({}), facts: z.object({}).optional(), context: z.object({}).optional()})}); export const mapNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("map"), payload: z.union([z.object({}), z.array(z.unknown())]), options: z.object({flat_map: z.boolean().optional()}).optional()}); export const staticNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("static"), payload: z.record(z.string(), z.unknown())}); export const delayNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("delay"), payload: z.object({time_ms: z.number().int().gte(0)})}); export const scheduleNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("schedule"), payload: z.object({flow_subject: z.string(), trigger: z.unknown(), trigger_in: z.string().optional(), trigger_on: z.string().optional()})}); export const escalationPayload = z.object({message: z.string(), title: z.string().optional(), description: z.string().optional(), priority: z.string().optional(), assignees: z.string().optional(), fields: z.union([z.record(z.string(), z.unknown()), z.string()]).optional(), task_id: z.string().optional(), keep_status: z.boolean().optional()}); export const inputNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("input"), payload: escalationPayload}); export const humanInTheLoopNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("human-in-the-loop"), payload: escalationPayload}); export const quivaEndpointNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("quiva-endpoint"), subject: z.string(), payload: z.unknown()}); export const errorNodeData = z.object({id: z.string(), name: z.string().optional(), description: z.string().optional(), node_type: z.literal("error"), payload: z.object({status_code: z.number().int(), message: z.string().optional()})}); export const nodeData = z.discriminatedUnion("node_type", [triggerNodeData, agentNodeData, functionNodeData, integrationNodeData, httpNodeData, flowNodeData, evalNodeData, conditionNodeData, rulesNodeData, mapNodeData, staticNodeData, delayNodeData, scheduleNodeData, inputNodeData, humanInTheLoopNodeData, quivaEndpointNodeData, errorNodeData]); export const nodeWorkflow = z.object({id: z.string(), data: nodeData, position: z.object({}).optional()}); export const edge = z.object({id: z.string(), source: z.string(), target: z.string()}); export const workflowConfig = z.object({nodes: z.array(nodeWorkflow).optional(), edges: z.array(edge).optional(), static: z.object({}).optional(), result: z.string().optional(), options: z.object({run_type: z.enum(["normal", "debounced", "ordered"]).optional(), order_on: z.string().optional(), debounce_on: z.string().optional(), debounce_time: z.number().int().optional(), debounce_max: z.number().int().optional()}).optional()}); export const modified = z.number().int(); export const listWorkflowsResponse = z.object({results: z.array(z.object({subject: z.string().optional(), name: z.string().optional(), description: z.string().optional(), config: workflowConfig.optional(), modified: modified.optional()})).optional(), results_total: z.number().int().optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * List workflows * * GET /hub/workflows * * Also accepts auth: apiKeyAuth */ export const getApiHubWorkflows = async (args: GetApiHubWorkflowsArgs, options?: GetApiHubWorkflowsOptions) => { const {baseUrl = "https://api.quiva.ai", fetch: fetchFn = fetch, bearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.collection_topic != null) query.append("collection_topic", String(args.collection_topic)) if (args.version != null) query.append("version", String(args.version)) if (bearerAuth !== undefined) headers.set('authorization', `Bearer ${bearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/hub/workflows${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(listWorkflowsResponse, await res.json()) };