API Reference - tsrun
Description: tsrun API reference for Rust and C embedding.

# API Reference

## Rust API

### Basic Execution

rust

    use tsrun::{Interpreter, StepResult, JsValue};

    let mut interp = Interpreter::new();
    interp.prepare(r#"
        const greeting = "Hello";
        const target = "World";
        `${greeting}, ${target}!`
    "#, None)?;

    loop {
        match interp.step()? {
            StepResult::Continue => continue,
            StepResult::Complete(value) => {
                assert_eq!(value.as_str(), Some("Hello, World!"));
                break;
            }
            _ => break,
        }
    }

### ES Module Loading

The interpreter pauses when imports are needed:

rust

    use tsrun::{Interpreter, StepResult, ModulePath};

    let mut interp = Interpreter::new();

    // Main module with imports
    interp.prepare(r#"
        import { add } from "./math.ts";
        export const result = add(2, 3);
    "#, Some(ModulePath::new("/main.ts")))?;

    loop {
        match interp.step()? {
            StepResult::Continue => continue,
            StepResult::NeedImports(imports) => {
                for import in imports {
                    // Load module source from filesystem, network, etc.
                    let source = match import.resolved_path.as_str() {
                        "/math.ts" => "export function add(a, b) { return a + b; }",
                        _ => panic!("Unknown module"),
                    };
                    interp.provide_module(import.resolved_path, source)?;
                }
            }
            StepResult::Complete(value) => {
                println!("Done: {}", value);
                break;
            }
            _ => break,
        }
    }

### Working with Values

rust

    use tsrun::{Interpreter, api, JsValue};
    use serde_json::json;

    let mut interp = Interpreter::new();
    let guard = api::create_guard(&interp);

    // Create values from JSON
    let user = api::create_from_json(&mut interp, &guard, &json!({
        "name": "Alice",
        "age": 30,
        "tags": ["admin", "developer"]
    }))?;

    // Read properties
    let name = api::get_property(&user, "name")?;
    assert_eq!(name.as_str(), Some("Alice"));

    // Modify properties
    api::set_property(&user, "email", JsValue::from("alice@example.com"))?;

    // Call methods
    let tags = api::get_property(&user, "tags")?;
    let joined = api::call_method(&mut interp, &guard, &tags, "join", &[JsValue::from(", ")])?;
    assert_eq!(joined.as_str(), Some("admin, developer"));

### Async/Await with Orders

For async operations, the interpreter pauses with pending "orders" that the host fulfills:

rust

    use tsrun::{Interpreter, StepResult, OrderResponse, api};

    let mut interp = Interpreter::new();

    interp.prepare(r#"
        import { order } from "tsrun:host";
        const response = await request({ url: "/api/users" });
        response.data
    "#, Some("/main.ts".into()))?;

    loop {
        match interp.step()? {
            StepResult::Continue => continue,
            StepResult::Suspended { pending, cancelled } => {
                let mut responses = Vec::new();
                for order in pending {
                    // Examine order.payload to determine what to do
                    let response = api::create_response_object(&mut interp, &json!({
                        "data": [{"id": 1, "name": "Alice"}]
                    }))?;
                    responses.push(OrderResponse {
                        id: order.id,
                        result: Ok(response),
                    });
                }
                interp.fulfill_orders(responses);
            }
            StepResult::Complete(value) => {
                println!("Result: {}", value);
                break;
            }
            _ => break,
        }
    }

### Accessing Module Exports

rust

    use tsrun::{Interpreter, StepResult, api};

    let mut interp = Interpreter::new();
    interp.prepare(r#"
        export const VERSION = "1.0.0";
        export const CONFIG = { debug: true };
    "#, Some("/config.ts".into()))?;

    // Run to completion
    loop {
        match interp.step()? {
            StepResult::Continue => continue,
            StepResult::Complete(_) => break,
            _ => break,
        }
    }

    // Access exports
    let version = api::get_export(&interp, "VERSION");
    assert_eq!(version.unwrap().as_str(), Some("1.0.0"));

    let export_names = api::get_export_names(&interp);
    assert!(export_names.contains(&"VERSION".to_string()));
    assert!(export_names.contains(&"CONFIG".to_string()));

## C API

Build with C API support:

bash

    cargo build --release --features c-api

### Context Lifecycle

c

    #include "tsrun.h"

    int main() {
        // Create context
        TsRunContext* ctx = tsrun_new();

        // Prepare and run code
        tsrun_prepare(ctx, "1 + 2 * 3", NULL);
        TsRunStepResult result = tsrun_run(ctx);

        if (result.status == TSRUN_STEP_COMPLETE) {
            printf("Result: %g\n", tsrun_get_number(result.value));
            tsrun_value_free(result.value);
        }

        // Cleanup
        tsrun_step_result_free(&result);
        tsrun_free(ctx);
        return 0;
    }

### Native Functions

Register C functions callable from JavaScript:

c

    static TsRunValue* native_add(TsRunContext* ctx, TsRunValue* this_arg,
                                  TsRunValue** args, size_t argc,
                                  void* userdata, const char** error_out) {
        double a = tsrun_get_number(args[0]);
        double b = tsrun_get_number(args[1]);
        return tsrun_number(ctx, a + b);
    }

    int main() {
        TsRunContext* ctx = tsrun_new();

        // Register native function
        TsRunValueResult fn = tsrun_native_function(ctx, "add", native_add, 2, NULL);
        tsrun_set_global(ctx, "add", fn.value);

        // Use from JS
        tsrun_prepare(ctx, "add(10, 20)", NULL);
        TsRunStepResult result = tsrun_run(ctx);
        // result.value is 30.0

        tsrun_step_result_free(&result);
        tsrun_free(ctx);
        return 0;
    }

### Module Loading

c

    TsRunStepResult result = tsrun_run(ctx);

    while (result.status == TSRUN_STEP_NEED_IMPORTS) {
        for (size_t i = 0; i < result.import_count; i++) {
            const char* path = result.imports[i].resolved_path;
            const char* source = load_from_filesystem(path);
            tsrun_provide_module(ctx, path, source);
        }
        tsrun_step_result_free(&result);
        result = tsrun_run(ctx);
    }

### Creating Values

c

    // Primitives
    TsRunValue* num = tsrun_number(ctx, 42.0);
    TsRunValue* str = tsrun_string(ctx, "hello");
    TsRunValue* b = tsrun_boolean(ctx, true);
    TsRunValue* null = tsrun_null(ctx);
    TsRunValue* undef = tsrun_undefined(ctx);

    // Objects
    TsRunValue* obj = tsrun_object(ctx);
    tsrun_set(ctx, obj, "name", tsrun_string(ctx, "Alice"));
    tsrun_set(ctx, obj, "age", tsrun_number(ctx, 30));

    // Arrays
    TsRunValue* arr = tsrun_array(ctx, 3);
    tsrun_set_index(ctx, arr, 0, tsrun_number(ctx, 1));
    tsrun_set_index(ctx, arr, 1, tsrun_number(ctx, 2));
    tsrun_set_index(ctx, arr, 2, tsrun_number(ctx, 3));

### Key Functions

Function | Description
--- | ---
`tsrun_new()` | Create new interpreter context
`tsrun_free(ctx)` | Free context and all associated memory
`tsrun_prepare(ctx, code, path)` | Prepare code for execution
`tsrun_run(ctx)` | Run until pause or completion
`tsrun_provide_module(ctx, path, src)` | Provide module source
`tsrun_native_function(...)` | Create native function
`tsrun_set_global(ctx, name, val)` | Set global variable
`tsrun_get(ctx, obj, key)` | Get object property
`tsrun_set(ctx, obj, key, val)` | Set object property
`tsrun_value_free(val)` | Free a value