mevento
v4.0.1
Published
MEvento is a tiny single-file scripting VM for host applications. The host keeps control of native behavior by exposing functions, while scripts stored in a database or loaded at runtime can compose those functions without rebuilding the host app.
Readme
MEvento TypeScript
MEvento is a tiny single-file scripting VM for host applications. The host keeps control of native behavior by exposing functions, while scripts stored in a database or loaded at runtime can compose those functions without rebuilding the host app.
This module is the TypeScript implementation. It provides synchronous
MEvento and async MEventoAsync runtimes.
v2 Status
v2 is a superset of v1 script syntax, with stricter diagnostics and new runtime helpers. Existing v1 scripts should still parse and execute in v2.
By default, v2 is stricter: unknown host functions raise unknown_function
instead of silently returning null. For existing database scripts that depend
on the v1 behavior, run the VM with { compatV1: true }. In that mode, missing
host functions return null and instance validation does not report them as
unknown. New scripts should prefer strict mode and wrap risky calls in _try_
when a script should continue after failure.
v2 additions include:
- Dot property access:
user.nameis equivalent touser['name']. _try_result capture and helper functions.- Function specs with arity, argument type hints, tags, return type hints, and optional documentation metadata.
- Script manifest validation for required host functions, inputs, and outputs.
- Trace mode and execution step budgets.
- v1 compatibility mode for existing scripts that call optional host functions.
- Minimal collection built-ins for arrays and maps.
Script Syntax
MEvento is intentionally small and C-like. It has no user-defined functions and no classes. The host application owns the real logic.
Supported syntax includes assignments, expressions, host calls, object and
array literals, bracket and dot access, if, while, numeric for,
for ... in, break, continue, return, ??, comments, and multilingual
keyword dictionaries.
Example:
user = loadUser()
name = user.profile.name ?? 'anonymous'
items = []
_push_(items, name)
if (_len_(items) > 0) {
log(items[0])
}Built-In Functions
Result helpers:
_try_(expression) # returns {ok, value, error}; evaluates lazily
_ok_(result)
_err_(result)
_value_(result, fallback)
_error_(result)
_code_(result)
_message_(result)
_unwrap_(result)Collection helpers:
_len_(array|object|string)
_push_(array, value) # mutates array, returns array
_pop_(array) # mutates array, returns removed value or null
_insert_(array, index, value)
_remove_at_(array, index) # mutates array, returns removed value or null
_has_(object, key)
_keys_(object)
_values_(object)Invalid built-in argument types raise invalid_argument_type and can be
captured with _try_.
Usage
Register global functions:
import { MEvento } from "mevento";
MEvento.register("log", (args) => {
console.log(...args);
return null;
});
MEvento.register("add", (args) => Number(args[0]) + Number(args[1]), {
name: "add",
description: "Adds two numeric values.",
minArgs: 2,
maxArgs: 2,
args: [
{ name: "left", type: "number", description: "First value." },
{ name: "right", type: "number", description: "Second value." },
],
returnType: "number",
returnDescription: "The sum of the two values.",
examples: [{ script: "add(12, 23)", result: 35 }],
metadata: { category: "math" },
});
const value = MEvento.run("add(12, 23)");Use one VM instance:
import { MEvento } from "mevento";
const vm = MEvento.newInstance();
vm.registerFunction("loadUser", () => ({ profile: { name: "Awa" } }), {
name: "loadUser",
maxArgs: 0,
returnType: "object",
});
const result = vm.execute("loadUser().profile.name");Use async host functions:
import { MEventoAsync } from "mevento";
const vm = MEventoAsync.newInstance();
vm.registerFunction("fetchUser", async () => ({ name: "Awa" }), {
name: "fetchUser",
maxArgs: 0,
returnType: "object",
});
const name = await vm.execute("fetchUser().name");Inject host input for one run:
const total = MEvento.run("base + bonus", false, {
base: 12,
bonus: 23,
});Documenting Host Functions
Function and argument specs can carry optional documentation metadata:
description, returnDescription, examples, and metadata on functions,
plus description and metadata on arguments. The runtime exposes those fields
through capabilities() for diagnostics, documentation, and UI tooling, but
they do not change script execution.
Validation And Manifests
Function specs drive preflight validation and runtime argument checks:
const validation = vm.validate("add(12)");
if (!validation.ok) {
console.log(validation.errors);
}Manifest validation checks required functions, inputs, and outputs:
const manifest = {
functions: {
add: { name: "add", minArgs: 2, maxArgs: 2, returnType: "number" },
},
inputs: [{ name: "base", type: "number" }],
outputs: [{ name: "result", type: "number" }],
};
const checked = MEvento.validateManifestSource(
"result = add(base, 2)",
manifest,
);Options: Compatibility, Trace And Budgets
Use options to enable v1 compatibility for existing scripts, cap execution steps, or collect a lightweight trace:
const legacyVm = MEvento.newInstance({ compatV1: true });
legacyVm.execute("optionalHostFunction()"); // returns null when missing
const vm = MEvento.newInstance({ maxSteps: 1000, trace: true });
vm.execute("log('ok')");
const trace = vm.trace();Development
npm install
npm run build
npm run test:conformanceThe package currently uses a custom conformance command. Do not use npm test
unless package metadata is updated.
