Skip to content

DynamicExecutor Module

Introduction

The DynamicExecutor class is a part of a low-code pipeline framework aimed at executing arbitrary code dynamically. It allows code execution with an optional configuration that controls various aspects like timeout, logging, environment variables, and more.

Table of Contents

Quick Start

ts
import { DynamicExecutor } from "@idealeap/pipeline";

const executor = new DynamicExecutor({ logging: true });

const result = await executor.execute("return args[0] + args[1]", 1, 2);
console.log(result); // Output: 3
import { DynamicExecutor } from "@idealeap/pipeline";

const executor = new DynamicExecutor({ logging: true });

const result = await executor.execute("return args[0] + args[1]", 1, 2);
console.log(result); // Output: 3

Type Definitions

ExecutorConfig

An interface to specify configuration options for the DynamicExecutor.

ts
interface ExecutorConfig {
  timeout?: number;
  logging?: boolean;
  environment?: Record<string, any>;
  allowedBuiltins?: string[];
  beforeExecute?: (code: string) => void;
  afterExecute?: (result: any, code: string, error?: Error) => void;
  validateCode?: (code: string) => boolean;
}
interface ExecutorConfig {
  timeout?: number;
  logging?: boolean;
  environment?: Record<string, any>;
  allowedBuiltins?: string[];
  beforeExecute?: (code: string) => void;
  afterExecute?: (result: any, code: string, error?: Error) => void;
  validateCode?: (code: string) => boolean;
}

API

DynamicExecutor Class

constructor(config?: ExecutorConfig)

Creates a new instance of the DynamicExecutor with optional configuration.

execute<T = any>(code: string, ...args: any[]): Promise<T | null>

Executes the provided code and returns a Promise that resolves to the result or null if an error occurs.

static run(params: { code: string; config?: ExecutorConfig }): Promise<any>

Static method to run a code block with an optional configuration.

Examples

Basic Usage

ts
const executor = new DynamicExecutor();
const result = await executor.execute("return args[0] * 2", 5);
console.log(result); // Output: 10
const executor = new DynamicExecutor();
const result = await executor.execute("return args[0] * 2", 5);
console.log(result); // Output: 10

With Timeout

ts
const executor = new DynamicExecutor({ timeout: 1000 });
const result = await executor.execute("while(true);", 5);
console.log(result); // Output: Error - Timeout
const executor = new DynamicExecutor({ timeout: 1000 });
const result = await executor.execute("while(true);", 5);
console.log(result); // Output: Error - Timeout

With Logging

ts
const executor = new DynamicExecutor({ logging: true });
const result = await executor.execute("return args[0] + args[1]", 1, 2);
const executor = new DynamicExecutor({ logging: true });
const result = await executor.execute("return args[0] + args[1]", 1, 2);

Using Before and After Hooks

ts
const config: ExecutorConfig = {
  beforeExecute: (code) => {
    console.log(`About to execute: ${code}`);
  },
  afterExecute: (result, code, error) => {
    if (error) {
      console.log(`Error during execution: ${error}`);
    } else {
      console.log(`Executed ${code} and got result ${result}`);
    }
  },
};

const executor = new DynamicExecutor(config);
const result = await executor.execute("return args[0] + args[1]", 1, 2);
const config: ExecutorConfig = {
  beforeExecute: (code) => {
    console.log(`About to execute: ${code}`);
  },
  afterExecute: (result, code, error) => {
    if (error) {
      console.log(`Error during execution: ${error}`);
    } else {
      console.log(`Executed ${code} and got result ${result}`);
    }
  },
};

const executor = new DynamicExecutor(config);
const result = await executor.execute("return args[0] + args[1]", 1, 2);

With Environment Variables

ts
const executor = new DynamicExecutor({
  logging: true,
  timeout: 5000,
  environment: { customVar: "Hello, world!" },
  allowedBuiltins: ["fetch"],
});

await(async () => {
  const result = await executor.execute<number | string | null>(
    `
  if (fetch) {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
      const data = await response.json();
      return data.id;
    } catch (e) {
      return 'Fetch failed';
    }
  } else {
    return customVar.length + args[0] + args[1];
  }
`,
    1,
    2,
  );
  expect(result).toEqual(16);
  console.log(result);
})();
const executor = new DynamicExecutor({
  logging: true,
  timeout: 5000,
  environment: { customVar: "Hello, world!" },
  allowedBuiltins: ["fetch"],
});

await(async () => {
  const result = await executor.execute<number | string | null>(
    `
  if (fetch) {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
      const data = await response.json();
      return data.id;
    } catch (e) {
      return 'Fetch failed';
    }
  } else {
    return customVar.length + args[0] + args[1];
  }
`,
    1,
    2,
  );
  expect(result).toEqual(16);
  console.log(result);
})();

Released under the MIT License.