Skip to content

Latest commit

 

History

History
225 lines (169 loc) · 9.02 KB

File metadata and controls

225 lines (169 loc) · 9.02 KB

Hako for .NET

箱 (Hako) means "box" in Japanese

License NuGet NuGet Downloads

Embeddable, lightweight, secure, high-performance JavaScript engine for .NET


What is Hako?

Hako is an embeddable JavaScript engine that brings modern ES2023+ JavaScript execution to your .NET applications. Built on 6over3's fork of QuickJS, Hako compiles QuickJS to WebAssembly and hosts it safely within your .NET process.

Hako supports the ES2023 specification and Phase 4 proposals including modules, asynchronous generators, top-level await, proxies, BigInt, and built-in TypeScript support.

What is Hako for .NET?

Hako for .NET is the official .NET host implementation that provides:

  • Secure Execution: JavaScript runs in a WebAssembly sandbox with configurable memory limits, execution timeouts, and resource controls
  • High Performance: Powered by QuickJS compiled to WASM, with multiple backend options (Wasmtime, WACS)
  • Modern JavaScript: Full ES2023+ support including async/await, modules, promises, classes, and more
  • TypeScript Support: Built-in type stripping for TypeScript code (type annotations are removed at runtime)
  • Top-Level Await: Use await at the module top level without wrapping in async functions
  • Deep .NET Integration: Expose .NET functions to JavaScript, pass complex types bidirectionally, and marshal data seamlessly
  • Lightweight: Minimal dependencies, small runtime footprint
  • Developer Friendly: Source generators for automatic binding, rich extension methods

Quick Start

dotnet add package Hako
dotnet add package Hako.Backend.Wasmtime
using Hako;
using Hako.Backend.Wasmtime;
using Hako.Extensions;

// Initialize the runtime
using var runtime = Hako.Initialize<WasmtimeEngine>();
using var realm = runtime.CreateRealm()
    .WithGlobals(g => g.WithConsole());

// Execute JavaScript with type-safe results
var result = await realm.EvalAsync<int>(@"
    const numbers = [1, 2, 3, 4, 5];
    const sum = numbers.reduce((a, b) => a + b, 0);
    console.log('Sum:', sum);
    sum;
");

Console.WriteLine($"Result from JS: {result}"); // 15

await Hako.ShutdownAsync();

Read the full technical documentation →

Top-Level Await

Use await directly at the module top level without wrapping in async functions:

var result = await realm.EvalAsync<string>(@"
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    data.message;
", new() { FileName = "app.js", Async = true  });

TypeScript Support

Hako automatically strips TypeScript type annotations when you use a .ts file extension:

var result = await realm.EvalAsync<int>(@"
    interface User {
        name: string;
        age: number;
    }

    function greet(user: User): string {
        return `${user.name} is ${user.age} years old`;
    }

    const alice: User = { name: 'Alice', age: 30 };
    console.log(greet(alice));

    alice.age + 12;
", new() { FileName = "app.ts" });

You can also manually strip types:

var typescript = "const add = (a: number, b: number): number => a + b;";
var javascript = runtime.StripTypes(typescript);

What Makes Hako Secure?

WebAssembly Sandboxing

All JavaScript execution happens inside a WebAssembly sandbox. The WASM runtime provides memory isolation, preventing JavaScript from accessing host memory outside its allocated boundaries.

Configurable Resource Limits

var runtime = Hako.Initialize<WasmtimeEngine>(opts => {
    opts.MemoryLimitBytes = 50 * 1024 * 1024; // 50 MB max
    opts.MaxStackSize = 1024 * 1024;          // 1 MB stack
});

realm.SetInterruptHandler(InterruptHandlers.Deadline(
    TimeSpan.FromSeconds(5) // 5 second timeout
));

Controlled Host Access

JavaScript can only access .NET functionality you explicitly expose:

realm.WithGlobals(g => g
    .WithConsole()
    .WithFunction("readFile", ReadFileFunction)
    .WithFunction("allowedAPI", AllowedAPIFunction));
// No file system, no network, no reflection—unless you provide it

Architecture

┌─────────────────────────────────────────┐
│         Your .NET Application           │
├─────────────────────────────────────────┤
│           Hako Runtime API              │
│  (Realm, JSValue, Module System, etc.)  │
├─────────────────────────────────────────┤
│         Backend Abstraction             │
│    ┌──────────────┬──────────────┐      │
│    │  Wasmtime    │    WACS      │      │
│    │  Backend     │   Backend    │      │
│    └──────────────┴──────────────┘      │
├─────────────────────────────────────────┤
│      Hako Engine (compiled to WASM)     │
│          ES2023+ JavaScript             │
└─────────────────────────────────────────┘

Projects

This repository contains multiple packages:

Package Description NuGet
Hako Core JavaScript runtime and APIs NuGet
Hako.Backend.Wasmtime wasmtime backend NuGet
Hako.Backend.WACS WACS backend NuGet
Hako.SourceGenerator Automatic binding generator NuGet
Hako.Backend Backend abstraction interfaces NuGet

Features

  • ES2023 specification and Phase 4 proposals
  • Top-level await
  • TypeScript type stripping (not type checking)
  • Async/await and Promises
  • Asynchronous generators
  • ES6 Modules (import/export)
  • Proxies and BigInt
  • Timers (setTimeout, setInterval, setImmediate)
  • Expose .NET functions to JavaScript
  • Expose .NET classes to JavaScript ([JSClass] source generation)
  • Marshal complex types bidirectionally
  • Custom module loaders
  • Bytecode compilation and caching
  • Multiple isolated realms
  • Memory and execution limits
  • Rich extension methods for safe API usage
  • No reflection. AOT is fully supported. See backends for more information.

Resources

Examples

Check out the examples/ directory for complete samples:

  • basics - Hello world and basic evaluation
  • host-functions - Exposing .NET functions to JavaScript
  • classes - Creating JavaScript classes backed by .NET
  • modules - ES6 module system and custom loaders
  • typescript - TypeScript type stripping
  • marshaling - Complex type marshaling between .NET and JS
  • timers - setTimeout, setInterval, and event loop
  • iteration - Iterating over arrays, maps, and sets
  • scopes - Resource management with DisposableScope
  • safety - Memory limits, timeouts, and sandboxing
  • raylib - Full game engine bindings example

License

Licensed under the Apache License 2.0. See LICENSE for details.


Built for the .NET community

Star us on GitHubDownload from NuGet