Platform

Edge Export

Kemu Edge Export


Table of Contents

  1. Edge Export
  2. Export Modes: Javascript Library vs Shell Script
  3. Export Process
  4. Folder Structure
  5. Using the Exported Recipe
  6. SDK Helper Methods
  7. Integration Examples
  8. Deployment Considerations

 

Edge Export

Edge Export converts Kemu recipes into standalone Node.js applications that run independently of the Kemu platform. This enables:

  • Independent deployment: Run recipes on any server, cloud platform, or local machine
  • System integration: Embed recipe functionality into existing applications
  • Scalable architecture: Deploy multiple instances without platform dependencies
  • Note: Internet connection is required for Edge recipes to function unless you are on an enterprise plan.

The export process transforms visual recipe workflows into executable code while preserving all logic, connections, and custom functionality.

 

Export Modes: Javascript Library vs Shell Script

Kemu Edge Export supports two export modes optimized for different use cases:


Javascript Library Mode

  • Purpose: Creates a Node.js application for programmatic integration into existing projects
  • Execution: Run with node main.js or import as a module
  • Best For: Development environments, microservices, and applications requiring programmatic control

Shell Script Mode

  • Purpose: Creates a standalone executable with convenient startup scripts
  • Execution: Double-click start.bat (Windows) or start.sh (Linux/macOS)
  • Best For: Standalone deployment, non-technical users, and production environments

Key Difference: Shell Script mode includes startup scripts for easy execution, while both modes share identical core files and dependencies.

 

Export Process

UI Export Steps

To export a recipe from the Kemu UI:

  1. Click the Home icon (house) in the Kemu interface
  2. Select "Kemu Edge Export" from the available options
  3. Optionally rename the export folder (defaults to recipe name)
  4. Click the folder icon to choose the save location
  5. Select the export mode (Javascript Library or Shell Script)
  6. Click "Export" and wait for completion

The export process creates a complete, self-contained application package with all necessary dependencies and runtime components.

Custom Inputs

 

Folder Structure

An export package contains:

Recipe Name/
├── main.js                    # Main entry point for the recipe
├── package.json               # Node.js dependencies and configuration
├── package-lock.json         # Dependency lock file
├── recipe.kemu              # Recipe definition and configuration
├── .env                      # Environment variables and secrets
└── node_modules/            # Installed dependencies

Additional files (depending on export mode):

Shell Script Mode:

├── start.bat                # Windows startup script
└── start.sh                 # Linux/macOS startup script

With Custom Services:

└── services/                # Kemu services used by the recipe
    └── service-name@version/
        ├── dist/            # Compiled service code
        │   ├── processor.js  # Main service processor
        │   ├── manifest.json # Service metadata
        │   ├── variants/     # Service variants
        │   └── lib/          # Service libraries
        └── package.json      # Service-specific dependencies

Key Files:

  • main.js: Entry point that starts the recipe using Edge Runtime
  • package.json: Defines the project as a Workspace Configuration with Edge Runtime dependency
  • recipe.kemu: Complete recipe definition including widgets, connections, and custom logic
  • .env: Contains environment variables and all configured secrets for the recipe
  • services/: All Kemu service used by the recipe with compiled code and dependencies
  • start.bat/start.sh: Convenience scripts for Shell Script mode execution

 

Using the Exported Recipe

Basic Execution

Javascript Library Mode

  1. Install dependencies: npm install
  2. Start the recipe: node main.js

Shell Script Mode

  1. Install dependencies: npm install
  2. Start the recipe:
    • Windows: start.bat or node main.js
    • Linux/macOS: ./start.sh or node main.js


SDK Helper Methods

The Kemu Edge SDK provides comprehensive helper methods for working with recipes:

Available Methods


Basic Recipe Interaction

The default main.js file contains:

import kemuEdge from '@kemu-io/edge-runtime'; console.log('Starting recipe...'); await kemuEdge.start(); console.log('Recipe running...'); // To Send data to input widgets /* import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); await recipe.sendToInputWidget('INPUT_NAME', { type: DataType.Number, value: 123 }); */

The start method initializes the Edge Runtime and begins executing your recipe. It returns a Recipe Instance that provides methods for interacting with your recipe. The commented section provides an example about how to interact with the exported recipe by sending data to an Input Widget.


Terminating the Recipe

The terminate method allows you to gracefully shut down the Edge Runtime and stop all recipe processing.

import kemuEdge from '@kemu-io/edge-runtime'; // Start the recipe await kemuEdge.start(); console.log('Recipe running...'); // ... your application logic ... // Terminate the recipe when done await kemuEdge.terminate(); console.log('Recipe terminated');

Note: The terminate method is asynchronous and should be awaited to ensure proper cleanup before your application exits.


Data Types

import { DataType } from '@kemu-io/edge-runtime'; // Available data types DataType.Number // Numeric data (integer or floating point) DataType.String // Text data DataType.ArrayBuffer // Raw binary data buffer DataType.Array // Array of items DataType.Boolean // True/false values DataType.JsonObj // JavaScript object (JSON-compatible) DataType.Anything // Accepts any data type (used by actions that don't care about the value) DataType.ImageData // Raw image data (produced in browser environments) DataType.AudioBuffer // Raw audio data buffer DataType.Rect // Rectangle with width, height, top, left properties DataType.Point // Point with x, y coordinates DataType.ImageBitmap // Image bitmap data DataType.BinaryFile // Custom binary data with format specification (e.g., `'image/png'`, `'audio/mp3'`)

Sending Data to Input Widgets

Input Widgets serve as the entry points for external data into your Kemu recipe. They act as receivers that accept data from your application code and pass it into the recipe workflow. This is the primary way to:

  • Trigger recipe execution: Send data to start or continue recipe processing
  • Provide external inputs: Feed data from your application into the recipe
  • Control recipe flow: Use different input widgets to handle different types of data
  • Integrate with external systems: Connect your application logic with Kemu recipe workflows

Important: Input Widgets must be configured in your recipe with specific names and data types. Your code must send data that exactly matches these configurations for successful communication.

Requirements:

  1. Name Match: The Input Widget name in your recipe must exactly match the name passed to sendToInputWidget()
  2. Data Type Match: The Input Widget's configured data type must match the DataType used in your code (see Data Type Mapping)
import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Send string data (Input Widget must be named "greeting" and configured as "String" type) await recipe.sendToInputWidget('greeting', { type: DataType.String, value: 'Hello World!' }); // Send image data (Input Widget must be named "process-image" and configured as "Image" type) await recipe.sendToInputWidget('process-image', { type: DataType.ImageData, value: imageData }); // Send JSON object (Input Widget must be named "userData" and configured as "Object" type) await recipe.sendToInputWidget('userData', { type: DataType.JsonObj, value: { id: 1, name: 'John Doe', email: 'john@example.com' } });

Common mistakes:

  • Code calls 'process-image' but Input Widget is named 'image'Will fail
  • Code uses DataType.ImageData but Input Widget is configured as "String" type → Will fail

Error Example: If you send the wrong data type, you'll see an error like:

Invalid data type: 0 for input: name. Expected: 1

This means the Input Widget expects a String (type 1) but a Number (type 0) was sent.



Sending Data and Waiting for Output

The sendToInputWidgetAndWaitForOutput method allows you to send data to an input widget and wait for the response from an output widget in the execution path. This is ideal for synchronous workflows where you need to wait for the recipe to complete processing before continuing.

This method is useful for:

  • Synchronous operations: Wait for recipe processing to complete before proceeding
  • Direct result retrieval: Get the output value directly without setting up listeners
  • Simplified code flow: Use async/await pattern instead of event listeners
  • API integrations: Return processed results directly in API responses
import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Send data and wait for the output widget response const result = await recipe.sendToInputWidgetAndWaitForOutput('process-data', { type: DataType.String, value: 'Hello World' }); console.log('Recipe result:', result); // The result contains the value sent to the output widget in the execution path

Important: This method requires an Output Widget in the execution path from the input widget. If no output widget is reached, the promise will hang indefinitely.



Global Variables Management

Global variables allow you to share data across your recipe and interact with it from external code. The global variables API provides methods to monitor, set, retrieve, and manage variables programmatically.

Available Methods:

  • onChange(varName, callback) - Listen for changes to a specific global variable
  • onChange('*', callback) - Listen for changes to all global variables
  • setValue(varName, value, config?) - Set the value of a global variable
  • getValue(varName) - Get the current value of a global variable
  • getAll() - Get all global variables
  • delete(varName) - Remove a global variable

Listening for Variable Changes:

import kemuEdge from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Listen for changes to a specific variable recipe.globalVariables.onChange('output-image', (variable) => { console.log('Output image updated:', variable.lastValue); console.log('Variable name:', variable.name); console.log('Previous value:', variable.previousValue); }); // Listen for changes to all variables recipe.globalVariables.onChange('*', (variable) => { console.log('Any variable changed:', variable.name, variable.lastValue); }); // Send data to trigger variable updates await recipe.sendToInputWidget('process-image', imageData);

Setting and Getting Variables:

import kemuEdge from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Set a global variable value await recipe.globalVariables.setValue('savePath', '/path/to/output.png'); // Set with options to control notifications await recipe.globalVariables.setValue('config', { quality: 90, format: 'jpeg' }, { disableChangeNotifications: false, // Don't trigger change listeners disableDefineNotifications: false, // Don't trigger define listeners doNotOverrideExisting: false // Allow overwriting existing values }); // Get a specific variable const savePath = recipe.globalVariables.getValue('savePath'); console.log('Save path:', savePath?.lastValue); // Get all variables const allVariables = recipe.globalVariables.getAll(); console.log('All variables:', allVariables); // Delete a variable recipe.globalVariables.delete('savePath');

Unsubscribing from Changes:

The onChange method returns an unsubscribe function for cleanup:

const unsubscribe = recipe.globalVariables.onChange('output-image', (variable) => { console.log('Image updated:', variable.lastValue); // Stop listening after first update if (variable.lastValue) { unsubscribe(); } });


Status Monitoring

Status widgets allow your recipe to communicate status updates that can be monitored from external code. This is useful for tracking progress, errors, or state changes in your recipe workflows.

Listening for Status Changes:

import kemuEdge from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Listen for any status value changes recipe.status.onChange((status) => { console.log('Status changed:', status.name); console.log('Status value:', status.value); console.log('Source widget:', status.sourceWidget); console.log('Status widget ID:', status.statusWidgetId); }); // Send data that triggers status updates await recipe.sendToInputWidget('setStatus', 'processing');

Unsubscribing from Status Changes:

const unsubscribe = recipe.status.onChange((status) => { console.log('Status:', status); // Stop listening after specific condition if (status.value.type === DataType.String && status.value.value === 'complete') { unsubscribe(); } });


Edge Functions

Edge functions allow you to register custom JavaScript handlers that can be called from within your recipe. This enables powerful customization where your recipe can invoke external code functions dynamically.

Registering a Function Handler:

import kemuEdge from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Register a handler for an edge function recipe.edgeFunctions.register('do-something', async (event) => { console.log('Edge function called with:', event); // Perform custom logic const result = await performCustomOperation(event.data); // Return the result return result; }); // When the recipe calls the 'do-something' edge function, // your handler will be invoked with the event data. // You recipe will wait for the result of the function and send it to its output port.

Unregistering a Function Handler:

// Remove a specific handler recipe.edgeFunctions.unregister('do-something'); // Clear all registered handlers recipe.edgeFunctions.clearAll();


Image Processing and Loading

Loading Images from Different Sources

import kemuEdge, { utils, DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Load image from URL const image = await utils.loadImageFile('https://example.com/image.jpg'); // Load image from local file const localImage = await utils.loadImageFile('./path/to/image.jpg'); // Load image from Base64 string const base64String = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD...'; const imageFromBase64 = await utils.loadImageFile(base64String);

 

Integration Examples

Basic String Input with Asynchronous Output

This example demonstrates how to use an Input Widget as the entry point by using the sendToInputWidget asynchronous method, and receiving the result by monitoring global variable changes:


Drag the example onto the workspace to explore and experiment!



In this example:

  1. Input Widget (greeting) receives the string "Hello World!" from the external code
  2. Text Widget processes the input and generates a response "Hi there!"
  3. Variable Widget (greeting-response) stores the response as a global variable
  4. External Code receives the response through the global variable change listener and logs it to the console

Flow Summary: External Code → Input Widget → Text Widget → Global Variable → External Code Listener

How to Run This Example

  1. Export the recipe as "Javascript Library Mode" from Kemu Edge
  2. After exporting as a JavaScript library, open the exported project in your code editor (e.g., VS Code). The main.js file contains an example of how to start the recipe and send data to input widgets. By default, it looks like this:
import kemuEdge from '@kemu-io/edge-runtime'; console.log('Starting recipe...'); await kemuEdge.start(); console.log('Recipe running...'); // To Send data to input widgets /* import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); await recipe.sendToInputWidget('greeting', { type: DataType.Number, value: 123 }); */
  1. Replace the existing code with the code below (to simulate input after export)
import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; console.log('Starting recipe...'); const recipe = await kemuEdge.start(); console.log('Recipe running...'); // Set up listener for the response variable recipe.globalVariables.onChange('greeting-response', (variable) => { console.log('Received response:', variable.lastValue); console.log('Variable name:', variable.name); console.log('Previous value:', variable.previousValue); }); // Send data to the input named "greeting" await recipe.sendToInputWidget('greeting', { type: DataType.String, value: 'Hello World!' }); console.log('Greeting sent, waiting for response...');
  1. Open the exported folder in terminal and run:
    npm install node main.js

Note: If you enabled "Install dependencies" during export, npm install was already executed automatically. Key changes: Uncomment the example code, change DataType.Number to DataType.String, add the response listener, and modify the input value.

  1. Expected Output: The terminal will display:

    Starting recipe...
    Recipe running...
    Greeting sent, waiting for response...
    Received response: Hi there!
    Variable name: greeting-response
    Previous value: 

    The recipe processes the input string "Hello World!" and returns the greeting response "Hi there!" through the Variable Widget, which triggers the global variable change listener.

 

Basic String Input with Synchronous Output

This example demonstrates how to use an Input Widget as the entry point by using the sendToInputWidgetAndWaitForOutput synchronous method, and awaiting for the result provided by the Output Widget:


Drag the example onto the workspace to explore and experiment!



In this example:

  1. Input Widget (greeting) receives string data from external code via sendToInputWidgetAndWaitForOutput()
  2. Text Widget processes the input and generates a greeting response: "Hi there!"
  3. Output Widget transmits the final processed result directly back to external code

How to Run This Example

  1. Export the recipe as "Javascript Library Mode" from Kemu Edge
  2. Open the exported folder in your favorite code editor and modify the main.js file with the following code:
import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; console.log('Starting recipe...'); const recipe = await kemuEdge.start(); console.log('Recipe running...'); // Send data and wait for output directly const result = await recipe.sendToInputWidgetAndWaitForOutput('greeting', { type: DataType.String, value: 'Hello World' }); console.log('Recipe result:', result);
  1. Open the terminal and run:

    npm install node main.js

    Note: If you enabled "Install dependencies" during export, npm install was already executed automatically.

  2. Expected Output: The terminal will display:

    Starting recipe...
    Recipe running...
    Recipe result: Hi there!

    The recipe processes the input string "Hello World" and returns the greeting response "Hi there!" directly through the Output Widget.

 

Image Processing Integration

This example demonstrates a complete image processing workflow with file saving. The utils.encodeImageData method converts raw ImageData objects into common image file formats:


Drag the example onto the workspace to explore and experiment!



In this example:

  1. Input Widget (process-image) receives image data from external code via sendToInputWidget()
  2. Image Filter Widget applies grayscale filter to the received image
  3. Image Resize Widget resizes the filtered image to 100x100 pixels
  4. Variable Widget (image-processed) stores the processed result as a global variable
  5. External Code receives the processed image through the global variable change listener and saves it as a JPEG file

How to Run This Example

  1. Export the recipe as "Javascript Library Mode" from Kemu Edge
  2. Open the exported folder in your favorite code editor and modify the main.js file with the following code:
import path from 'path'; import fs from 'fs'; // NOTE: contains helper functions to manipulate images import kemuEdge, { utils, DataType } from '@kemu-io/edge-runtime'; // Start recipe const recipe = await kemuEdge.start(); // Load image from URL const image = await utils.loadImageFile('https://cdn.pixabay.com/photo/2012/01/09/09/10/sun-11582_1280.jpg'); console.log('Image loaded'); // Create a listener for when the image is processed recipe.globalVariables.onChange('image-processed', async (variable) => { try { const image = variable.lastValue; const targetPath = path.resolve('./image-processed.jpeg'); console.log(`Image processed, saving file to "${targetPath}"`); const jpgBuffer = await utils.encodeImageData(image, 'jpeg'); fs.writeFileSync(targetPath, jpgBuffer); process.exit(0); } catch(error) { console.error('Error saving image', error); process.exit(1); } }); // Send image to input widget await recipe.sendToInputWidget('process-image', { type: DataType.ImageData, value: image });

Note, some important code in the modify file:

  • utils.loadImageFile(url): Loads an image from a URL or file path and returns it as ImageData, which can be sent to the input widget
  • recipe.globalVariables.onChange('image-processed', async (variable) => { ... }): Listens for changes to the image-processed global variable, so you can react when the image processing is complete and save the result
  1. Open the terminal and run:

    npm install node main.js

    Note: If you enabled "Install dependencies" during export, npm install was already executed automatically.

  2. Expected Output: The terminal will display:

    Image loaded
    Image processed, saving file to "/path/to/your/exported/folder/image-processed.jpeg"

    The recipe processes the image from the URL, applies grayscale filter and resizes it to 100x100 pixels, then saves the result as image-processed.jpeg in the exported folder.

 

Express.js Integration

This example demonstrates how to integrate an Express server with a Kemu recipe by sending an API request with an imageUrl, which the recipe processes and returns as a Base64 string in the response:


Drag the example onto the workspace to explore and experiment!



In this example:

  1. Input Widget (process-image) receives ImageData from external code via sendToInputWidgetAndWaitForOutput()
  2. Image Filter Widget applies grayscale filter to the received image
  3. Image Resize Widget resizes the filtered image to 100x100 pixels
  4. Output Widget transmits the processed image directly back to external code
  5. External Code receives the processed image and converts it to Base64 for the API response

How to Run This Example

  1. Export the recipe as "Javascript Library Mode" from Kemu Edge
  2. Open the exported folder in your favorite code editor and modify the main.js file with the following code:
import express from 'express'; import kemuEdge, { utils, DataType } from '@kemu-io/edge-runtime'; const app = express(); app.use(express.json()); // Route that triggers the recipe app.post('/api/process-image', async (req, res) => { const { imageUrl } = req.body; const image = await utils.loadImageFile(imageUrl); console.log('Starting recipe...'); const recipe = await kemuEdge.start(); // Send image to input widget const result = await recipe.sendToInputWidgetAndWaitForOutput('process-image', { type: DataType.ImageData, value: image }); const jpgBuffer = await utils.encodeImageData(result, 'jpeg'); res.json({ success: true, image: `data:image/jpeg;base64,${jpgBuffer.toString('base64')}` }); }); // Start the server app.listen(3000, () => console.log('Server running on port 3000'));
  1. Open the terminal and run:

    npm install express node main.js

    Note: If you enabled "Install dependencies" during export, npm install was already executed automatically.

  2. Test the API using Postman:

    • Method: POST
    • URL: http://localhost:3000/api/process-image
    • Headers: Content-Type: application/json
    • Body (raw JSON):
      { "imageUrl": "https://cdn.pixabay.com/photo/2012/01/09/09/10/sun-11582_1280.jpg" }
  3. Expected Output:

    • Terminal: The server will display:
      Server running on port 3000
      
    • Postman Response: The API will return a JSON response:
      { "success": true, "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..." }

    The recipe processes the image from the URL, applies grayscale filter and resizes it to 100x100 pixels, then returns the processed image as a Base64 string in the API response.

 

Deployment Considerations

System Requirements

  • Node.js: Version 22.2.0 or higher required
  • Platform Support: Windows, macOS, and Linux (multiple architectures)
  • Memory: Adequate RAM for image processing workflows
  • Storage: Space for dependencies and temporary files

Best Practices

  • Testing: Test exported recipes in target environment before deployment
  • Error Handling: Implement proper error handling in custom logic
  • Resource Monitoring: Monitor CPU and memory usage for independent Recipe Instances
  • Process Management: Use process managers like PM2 for production deployments
  • Security: Consider security implications when exposing webhooks publicly

Performance Considerations

  • Image Processing: Large images may require significant memory allocation
  • Concurrent Requests: Monitor resource usage under high load
  • Service Initialization: Allow adequate startup time for Service Dependencies initialization

 

Glossary

  • Edge Runtime

    The standalone execution environment that runs exported Kemu recipes independently of the Kemu platform. It provides the necessary APIs and utilities for interacting with recipes programmatically.

  • Recipe Instance

    The object returned by kemuEdge.start() that provides methods for sending data to input widgets and managing recipe execution. Each recipe instance represents a running copy of your exported recipe.

  • Event Listener

    A callback function that responds to specific events in the recipe, such as variable changes or widget outputs. Listeners allow external code to react to recipe state changes in real-time.

  • Data Type Mapping

    The correspondence between Kemu Edge data types (like DataType.String, DataType.Number) and the data types configured in your recipe widgets. Proper mapping is essential for successful data transmission.

  • Recipe State

    The current values and configuration of all widgets in a running recipe. The state persists during recipe execution and can be monitored through variable change listeners.

  • Export Package

    The complete set of files generated when exporting a recipe, including the recipe definition, dependencies, runtime components, and any custom services used by the recipe.

  • Service Dependencies

    Additional Kemu services (like custom widgets or external integrations) that your recipe requires to function. These are automatically included in the export package when present.

  • Workspace Configuration

    The package.json file in exported recipes that defines the project as a workspace with Kemu Edge Runtime as a dependency, enabling proper module resolution and execution.

  • Process Management

    The handling of recipe lifecycle events like startup, execution, and termination. Proper process management ensures clean resource cleanup and prevents memory leaks in long-running applications.