A powerful, safe, and extensible script execution engine with injectable context providers
Synthase is a TypeScript/JavaScript execution engine designed for running user-generated scripts safely with rich context injection, comprehensive validation, and intelligent caching. Perfect for building scriptable applications, automation platforms, and domain-specific tools.
- π‘οΈ Safe Execution - Comprehensive script validation, execution limits, and resource monitoring
- π§© Injectable Context - Modular context providers for different domains (Minecraft, data analysis, web APIs, etc.)
- β‘ High Performance - Intelligent caching, dependency resolution, and optimized execution
- π Rich Type System - Enhanced parameter definitions with validation, defaults, and conditional visibility
- π Hot Reloading - Dynamic script reloading for development workflows
- π¦ Dependency Management - Script registries and dynamic imports with safety checks
- π§ Highly Configurable - Execution limits, resource monitoring, and caching policies
npm install synthase
# or
bun add synthaseimport { execute } from "synthase";
const script = `
export const io = {
inputs: {
name: { type: 'string', default: 'World' },
count: { type: 'int', default: 3, min: 1, max: 10 }
},
outputs: {
message: { type: 'string' }
}
};
export default async function({ name, count }, { Logger }) {
Logger.info(\`Greeting \${name} \${count} times\`);
const message = Array(count).fill(\`Hello, \${name}!\`).join(' ');
return { message };
}`;
const result = await execute(script, { name: "Synthase", count: 2 });
console.log(result.message); // "Hello, Synthase! Hello, Synthase!"Synthase's power comes from its injectable context system. Instead of hardcoding dependencies, you inject context providers for different domains:
const dataContext = {
Statistics: {
mean: (values: number[]) =>
values.reduce((a, b) => a + b, 0) / values.length,
median: (values: number[]) => {
const sorted = [...values].sort((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
return sorted.length % 2
? sorted[mid]
: (sorted[mid - 1] + sorted[mid]) / 2;
},
},
DataProcessing: {
normalize: (values: number[]) => {
const max = Math.max(...values);
const min = Math.min(...values);
return values.map((v) => (v - min) / (max - min));
},
},
};
const analysisScript = `
export const io = {
inputs: {
dataset: { type: 'array' }
},
outputs: {
summary: { type: 'object' }
}
};
export default async function({ dataset }, { Statistics, DataProcessing }) {
const values = dataset.map(item => item.value);
return {
summary: {
mean: Statistics.mean(values),
median: Statistics.median(values),
normalized: DataProcessing.normalize(values)
}
};
}`;
const data = [{ value: 10 }, { value: 20 }, { value: 30 }];
const result = await execute(
analysisScript,
{ dataset: data },
{ contextProviders: dataContext }
);Synthase scripts are ES6 modules with two required exports:
export const io = {
inputs: {
// Simple type definition
message: { type: "string", default: "Hello" },
// Advanced parameter with validation
count: {
type: "int",
default: 1,
min: 1,
max: 100,
description: "Number of repetitions",
},
// Conditional parameter
advanced: { type: "boolean", default: false },
threshold: {
type: "float",
default: 0.5,
dependsOn: { advanced: true }, // Only show if advanced = true
},
// Options/enum
mode: {
type: "string",
default: "fast",
options: ["fast", "balanced", "quality"],
},
},
outputs: {
result: { type: "string" },
metadata: { type: "object" },
},
};export default async function (inputs, context) {
// inputs: validated parameters with defaults applied
// context: injected dependencies + base context (Logger, Calculator, Utils, importScript)
const { message, count } = inputs;
const { Logger, Calculator } = context;
Logger.info(`Processing: ${message}`);
return {
result: message.repeat(count),
metadata: { timestamp: new Date().toISOString() },
};
}Synthase includes comprehensive safety features:
- Syntax checking - Validates ES6 module syntax
- Security scanning - Detects dangerous patterns (eval, infinite loops, etc.)
- IO schema validation - Ensures proper input/output definitions
- Dependency analysis - Tracks and validates script imports
- Execution timeouts - Configurable max execution time
- Memory monitoring - Tracks and limits memory usage
- Import limits - Prevents import bombs and recursion
- Resource monitoring - Real-time resource usage tracking
- Type checking - Validates parameter types and ranges
- Default values - Applies defaults for missing parameters
- Conditional parameters - Shows/hides parameters based on dependencies
import { createReusable } from "synthase";
const reusable = await createReusable(script, { contextProviders });
// Execute multiple times with different inputs
const result1 = await reusable.execute({ name: "Alice" });
const result2 = await reusable.execute({ name: "Bob" });
reusable.dispose(); // Clean up resourcesimport { InMemoryScriptRegistry, HttpScriptRegistry } from "synthase";
// In-memory registry
const registry = new InMemoryScriptRegistry();
registry.register("helper-script", helperScriptContent);
// HTTP registry for loading from URLs
const httpRegistry = new HttpScriptRegistry("https://my-scripts.com/");
// Use with Synthase
const result = await execute(mainScript, inputs, {
registry,
contextProviders,
});import { createHotReloadable } from "synthase";
const getScript = () => fs.readFileSync("script.js", "utf8");
const hotReloadable = await createHotReloadable(getScript);
// Execute
let result = await hotReloadable.execute(inputs);
// Reload when file changes
await hotReloadable.reload();
result = await hotReloadable.execute(inputs); // Uses updated scriptconst result = await execute(script, inputs, {
contextProviders,
cachePolicy: {
maxAge: 10 * 60 * 1000, // 10 minutes
maxSize: 50, // max 50 cached scripts
},
});interface SynthaseConfig {
// Script registry for dependency resolution
registry?: ScriptRegistry;
// Execution limits
limits?: {
timeout?: number; // Max execution time (default: 30s)
maxRecursionDepth?: number; // Max import depth (default: 10)
maxImportedScripts?: number; // Max imported scripts (default: 50)
maxMemory?: number; // Max memory usage (default: 100MB)
};
// Resource monitoring
resourceMonitor?: {
maxMemory?: number; // Memory limit
checkIntervalMs?: number; // Monitoring interval
};
// Cache policy
cachePolicy?: {
maxAge?: number; // Cache TTL
maxSize?: number; // Max cached scripts
};
// Injectable context providers
contextProviders?: ContextProvider;
}Execute a script once with given inputs.
Execute with enhanced input validation against IO schema.
Validate script without executing - returns IO schema and dependencies.
Execute multiple scripts in sequence.
Create a reusable Synthase instance.
Execute the script with given inputs.
Get the script's IO schema.
Reload the script (for hot reloading).
Clean up resources.
Create a reusable script executor.
Create a hot-reloadable script executor.
Benchmark script performance.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes with tests
- Run the test suite:
bun test - Submit a pull request
git clone https://github.com/Nano112/synthase.git
cd synthase
bun install
bun run buildcd dev-api
bun install
bun run devVisit http://localhost:3001 for the interactive test interface.
Built with β€οΈ