Appearance
Scripts Overview
ApiMeld scripts are the core of every task. Each task has a single script body written in one of six supported languages. Scripts run in a sandboxed subprocess — they cannot access the host filesystem, read application secrets, or escalate privileges.
Supported languages
| Language | Runtime | Use case |
|---|---|---|
| PowerShell | PowerShell 7 | Windows-style automation, Active Directory, REST APIs |
| JavaScript | Node.js 24 | Lightweight API calls, JSON manipulation |
| TypeScript | Node.js 24 + tsc | JavaScript with types — same capabilities, compiled before running |
| Python | Python 3 | Data processing, pandas/openpyxl, scientific tasks |
| Bash | Bash | Shell commands, file operations, system administration |
| C# | Roslyn (in-process) | Full .NET scripting — LINQ, async/await, strong typing, NuGet-compatible APIs |
The sandbox
Scripts run as a dedicated script-runner system user with no home directory, no login shell, and no access to /app/config (where ApiMeld stores its credentials). The app user that runs ApiMeld can sudo to script-runner only for the specific executables used to run scripts (pwsh, node, python3, bash).
This means a script — even a malicious one — cannot:
- Read
appsettings.Production.jsonor database credentials - Write to the application directory
- Install packages (npm and npx are blocked for
script-runner) - Access other tasks' data
Auth headers and credentials
Scripts never see raw credentials. If a task has an auth configuration (Basic Auth or custom header), the credentials are decrypted by ApiMeld at runtime and injected into the script's execution environment as a pre-built variable:
- PowerShell:
$AuthHeaders(hashtable) - JavaScript/TypeScript:
authHeaders(object) - C#:
AuthHeaders(Dictionary<string, string>) - Python:
AUTH_HEADERSenvironment variable (JSON string — parse withjson.loads()) - Bash:
AUTH_HEADERS_JSONenvironment variable (JSON string — parse withjq)
Logging
Use the injected logger object to emit structured log entries with colour-coded levels in the Run History viewer.
| Language | Logger | Method examples |
|---|---|---|
| PowerShell | $logger | $logger.Info(), $logger.Warn(), $logger.Error(), $logger.Debug() |
| JavaScript | logger | logger.info(), logger.warn(), logger.error(), logger.debug() |
| TypeScript | logger | logger.info(), logger.warn(), logger.error(), logger.debug() |
| C# | Logger | Logger.Info(), Logger.Warn(), Logger.Error(), Logger.Debug() |
| Python | stdout / stderr | print() → INFO, print(..., file=sys.stderr) → ERROR |
| Bash | stdout / stderr | echo → INFO, echo ... >&2 → ERROR |
powershell
# PowerShell
$logger.Info("Starting sync")
$logger.Warn("Rate limit approaching")
$logger.Error("Failed to connect: $($_.Exception.Message)")javascript
// JavaScript / TypeScript
logger.info('Starting sync')
logger.warn('Rate limit approaching')
logger.error('Failed to connect', err.message)python
# Python
import sys
print("Starting sync") # INFO
print("Something wrong", file=sys.stderr) # ERRORbash
# Bash
echo "Starting sync" # INFO
echo "Something wrong" >&2 # ERRORTimeouts
Every script execution has a timeout. The default is configurable from Admin → Settings. When a script exceeds its timeout, the process is killed and the run is marked TimedOut.
Scripts can check their remaining time by monitoring for CancellationToken signals (PowerShell/C# interop) or simply keeping execution time well within the configured limit.