Skip to content

Cocoar.JsEval

JavaScript/TypeScript execution library for .NET, built on Jint.

NuGetLicense

Features

  • JavaScript execution via Jint (ES2025 support)
  • Execution methods: ExecuteAsync(string) / ExecuteAsync(prepared module) (standard), Evaluate(string) / Evaluate(prepared), EvaluateAsync()
  • Pre-parsed scripts (Prepare() / PrepareModule()) for maximum throughput
  • Sandboxed() + AllowOnly / DenyTypes for untrusted rules with real CLR objects
  • TypeScript 6.0 transpilation with embedded compiler
  • fetch() API with opt-in sandboxing
  • Automatic .NET Task → JS Promise interop
  • console.log/warn/error/debug via ILogger
  • setTimeout/setInterval support
  • Extensible module system (HTTP, Database, SMTP, Templates, and more)
  • .d.ts generation for IntelliSense support
  • Built for .NET 10

Quick Start

dotnet add package Cocoar.JsEval.Engine

Basic JavaScript Execution

services.AddJsEval();
varengine=sp.GetRequiredService<JsEngine>();engine.SetValue("name","World");engine.Evaluate("var greeting = 'Hello, ' + name + '!';");varresult=engine.GetValue<string>("greeting");// "Hello, World!"

Untrusted Rules

Two independent axes, and an untrusted script wants both. Sandboxed() governs what a script can do on its own — strict mode, no eval/Function, no reflection, and memory, recursion, stack, array and regex limits. AllowOnly and DenyTypes govern what it can reach: passing an object otherwise grants everything reachable from it.

services.AddJsEval(b =>b.Sandboxed()// hardens the runtime, latches.AllowOnly(a =>a.Member((Customerc)=>c.Name).Member((Customerc)=>c.Age)).DenyTypes(typeof(DbContext),typeof(IServiceProvider)));

Sandboxed() latches in both directions — EnableFetch() before or after it throws — so the guarantee never depends on the order the builder is written in. It hardens the runtime but does not narrow the object graph; that is what AllowOnly is for. Isolation between scripts is the engine instance: resolve a separate engine per script source.

With ES Modules

services.AddJsEval(b =>b.AddModule<CommonModule>().AddModule<HttpModule>());
varengine=sp.GetRequiredService<JsEngine>();awaitengine.ExecuteAsync(@" import * as common from 'common'; export function newId() { return common.Guid.New().toString(); }");varid=engine.InvokeFunction("newId");// fresh GUID each call

ES-module semantics: top-level code runs once per unique script on a given engine — repeated ExecuteAsync calls return the cached module namespace. Put per-call work inside exported functions and invoke them via InvokeFunction. For true per-call re-execution use the lightweight Evaluate(string) path.

Pre-Parsed Scripts (for repeated execution)

// Parse once (thread-safe, cacheable)varprepared=JsEngine.Prepare("query.WhereResponsible(ctx.UserId);");// Execute many times — no re-parsingengine.SetValue("ctx",accessContext);engine.SetValue("query",queryBuilder);engine.Evaluate(prepared);

TypeScript Transpilation

dotnet add package Cocoar.JsEval.TypeScript
services.AddTsTranspiler();
vartranspiler=sp.GetRequiredService<TsTranspiler>();varjs=transpiler.Transpile(tsCode);// transpile onceawaitengine.ExecuteAsync(js);// execute

fetch()

services.AddJsEval(b =>b.EnableFetch());
constresponse=awaitfetch('https://api.example.com/data');constbody=awaitresponse.text();console.log(response.status,response.ok);

.NET async → JS Promise (automatic)

engine.SetValue("loadData",newFunc<string,Task<string>>(async id =>{returnawaitdb.FindAsync(id);}));
constdata=awaitloadData('item-123');// .NET Task becomes a Promise

Execution Methods

MethodModule SystemasyncPreparedUse Case
ExecuteAsync(string)YesYesNoStandard -- use when you don't know what's in the script
ExecuteAsync(JsPreparedModule)YesYesYesPre-parsed module -- reuse across calls
Evaluate(string)NoNoNoLightweight sync -- when you control the script
Evaluate(JsPreparedScript)NoNoYesMax performance -- pre-parsed, reusable, no module system
EvaluateAsync(string)NoYesNoLightweight async -- no modules but needs await

ExecuteAsync is the default/standard method for trusted integration scripts and provides the full module system. For tenant- or end-user-authored rules, resolve a Sandboxed() engine with an AllowOnly surface. Evaluate is a lightweight execution mode for scripts you control and know do not need modules.

Packages

PackageDescription
Cocoar.JsEvalCore: interfaces, helpers, JsFunction
Cocoar.JsEval.EngineJsEngine + fetch() + DI registration
Cocoar.JsEval.TypeScriptTypeScript 6.0 transpiler
Cocoar.JsEval.TsDefinition.d.ts generation for IntelliSense
Cocoar.JsEval.LinqJS arrow functions → real Expression trees for Marten / EF / LINQ2DB
Cocoar.JsEval.Module.CommonGuid, Sleep, Random
Cocoar.JsEval.Module.HttpFluent HTTP client
Cocoar.JsEval.Module.DatabaseSQL Server + PostgreSQL
Cocoar.JsEval.Module.SmtpEmail via MailKit
Cocoar.JsEval.Module.AngleSharpHTML parsing
Cocoar.JsEval.Module.TemplateScriban templates
Cocoar.JsEval.Module.LoggingMicrosoft.Extensions.Logging
Cocoar.JsEval.Module.VirtualFileSystemZio VFS

License

Apache-2.0 — COCOAR e.U.

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages