#!/usr/bin/env bun /** * Export workflow JSON from database * * Usage: * bun apps/sim/scripts/export-workflow.ts * * This script exports a workflow in the same format as the export API route. * It fetches the workflow state from normalized tables, combines it with metadata * and variables, sanitizes it, and outputs the JSON. * * Make sure DATABASE_URL or POSTGRES_URL is set in your environment. */ // Suppress console logs from imported modules - only JSON should go to stdout const originalConsole = { log: console.log, warn: console.warn, error: console.error, } console.log = () => {} console.warn = () => {} console.error = () => {} import { writeFileSync } from 'fs' import { eq } from 'drizzle-orm' import { db } from '../../../packages/db/db.js' import { workflow } from '../../../packages/db/schema.js' import { loadWorkflowFromNormalizedTables } from '../lib/workflows/persistence/utils.js' import { sanitizeForExport } from '../lib/workflows/sanitization/json-sanitizer.js' // ---------- CLI argument parsing ---------- const args = process.argv.slice(2) const workflowId = args[0] const outputFile = args[1] // Optional output filename if (!workflowId) { process.stderr.write( 'Usage: bun apps/sim/scripts/export-workflow.ts [output-file]\n' ) process.stderr.write('\n') process.stderr.write('Examples:\n') process.stderr.write(' bun apps/sim/scripts/export-workflow.ts abc123\n') process.stderr.write(' bun apps/sim/scripts/export-workflow.ts abc123 workflow.json\n') process.stderr.write('\n') process.stderr.write('Make sure DATABASE_URL or POSTGRES_URL is set in your environment.\n') process.exit(1) } // ---------- Main export function ---------- async function exportWorkflow(workflowId: string, outputFile?: string): Promise { try { // Fetch workflow metadata const [workflowData] = await db .select() .from(workflow) .where(eq(workflow.id, workflowId)) .limit(1) if (!workflowData) { process.stderr.write(`Error: Workflow ${workflowId} not found\n`) process.exit(1) } // Load workflow from normalized tables const normalizedData = await loadWorkflowFromNormalizedTables(workflowId) if (!normalizedData) { process.stderr.write(`Error: Workflow ${workflowId} has no normalized data\n`) process.exit(1) } // Get variables in Record format (as stored in database) type VariableType = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'plain' const workflowVariables = workflowData.variables as | Record | undefined // Prepare export state - match the exact format from the UI const workflowState = { blocks: normalizedData.blocks, edges: normalizedData.edges, loops: normalizedData.loops, parallels: normalizedData.parallels, metadata: { name: workflowData.name, description: workflowData.description ?? undefined, exportedAt: new Date().toISOString(), }, variables: workflowVariables, } // Sanitize and export - this returns { version, exportedAt, state } const exportState = sanitizeForExport(workflowState) const jsonString = JSON.stringify(exportState, null, 2) // Write to file or stdout if (outputFile) { writeFileSync(outputFile, jsonString, 'utf-8') process.stderr.write(`Workflow exported to ${outputFile}\n`) } else { // Output the JSON to stdout only process.stdout.write(`${jsonString}\n`) } } catch (error) { process.stderr.write(`Error exporting workflow: ${error}\n`) process.exit(1) } } // ---------- Execute ---------- exportWorkflow(workflowId, outputFile) .then(() => { process.exit(0) }) .catch((error) => { process.stderr.write(`Unexpected error: ${error}\n`) process.exit(1) })