---
title: 'Web & NodeJS'
description: "The @json-eval-rs/webcore package provides a unified high-level API for both Browser (WASM) and NodeJS environments. It handles loading the appropriate backend automatically."
navigation:
  icon: 'i-simple-icons-nodedotjs'
seo:
  title: 'Web & NodeJS'
  description: "The @json-eval-rs/webcore package provides a unified high-level API for both Browser (WASM) and NodeJS environments. It handles loading the appropriate backend automatically."
---

## Installation

### For Web (Bundlers: Vite, Webpack, etc.)

```bash
yarn add @json-eval-rs/webcore @json-eval-rs/bundler
```

-   `@json-eval-rs/webcore`: The high-level TS API.
-   `@json-eval-rs/bundler`: The WASM compilation target for bundlers.

### For Web (Vanilla JS / Browser script tag)

If you are not using a bundler (or require standard browser-compatible native ECMA script modules):

```bash
yarn add @json-eval-rs/webcore @json-eval-rs/vanilla
```

-   `@json-eval-rs/vanilla`: The WASM compilation target for vanilla browser execution.

### For NodeJS

```bash
yarn add @json-eval-rs/webcore @json-eval-rs/node
```

-   `@json-eval-rs/node`: The NodeJS bindings (via N-API/WASM).

## Quick Start (Node.js)

Node.js usage relies on the `@json-eval-rs/node` package to automatically register native bindings.

```typescript
import { JSONEval } from '@json-eval-rs/webcore';
import '@json-eval-rs/node'; 

const run = async () => {
    const evalInstance = new JSONEval({ schema });

    try {
        const result = await evalInstance.validate({ data });
        console.log(result.has_error);
    } finally {
        evalInstance.free();
    }
};

run();
```

## Quick Start (Web Bundler)

For frameworks like Vite, Webpack, Next.js, and NuxtJS, you need to import the WASM module and pass it during initialization.

```typescript
import { JSONEval } from '@json-eval-rs/webcore';
import * as wasmModule from '@json-eval-rs/bundler';

// 1. Initialize
// Explicitly passing wasmModule allows bundlers to handle the WASM loading correctly
const evalInstance = new JSONEval({
  schema: mySchema,
  wasmModule
});

// 2. Evaluate
const result = await evalInstance.evaluate({
  data: myData
});

// 3. Cleanup
evalInstance.free();
```

## Quick Start (Web Vanilla)

For standard browser environments without a bundler, the vanilla target exports an ES module friendly WASM package.

```typescript
import { JSONEval } from '@json-eval-rs/webcore';
import * as wasmModule from '@json-eval-rs/vanilla';

// Initialize exactly the same way as the bundler method:
const evalInstance = new JSONEval({
  schema: mySchema,
  wasmModule
});

// ... Evaluate and free
evalInstance.free();
```

## API Reference

### `JSONEval` Class

#### Constructor

```typescript
new JSONEval(options: {
  schema: SchemaObject | string;
  context?: object | string;
  data?: object | string;
  wasmModule?: any; // Required for web bundlers
})
```

#### `evaluate`

```typescript
await evaluate(options: {
  data: object | string;
  context?: object | string;
  paths?: string[]; // Selective evaluation paths
})
```

#### `validate`

```typescript
await validate(options: {
  data: object | string;
  context?: object | string;
})
```

Returns:
```typescript
{
  has_error: boolean;
  errors: Array<{
    path: string;
    message: string;
    rule: string;
    // ...
  }>;
}
```

#### `evaluateSubform`

```typescript
await evaluateSubform(options: {
  subformPath: string; // e.g. "#/items"
  data: object | string;
  paths?: string[]; // Selective paths within the subform item
})
```

#### `evaluateDependents`

```typescript
await evaluateDependents(options: {
  changedPaths: string[]; // e.g. ["items.0.qty"]
  data: object | string;
  context?: object | string;
  reEvaluate?: boolean; // Default: false
})
```

#### Advanced Methods

**`validatePaths`**
Targeted validation for specific paths only. Useful when you only need to check errors for one or more specific fields.
```typescript
const result = await evalInstance.validatePaths({
  data: string | object,
  context?: string | object,
  paths: string[]
});
```
*(Also available: `validatePathsOnly`, which checks validation rules but skips generating the full resolved schema object internally)*

**`evaluateOnly`**
Evaluates the schema state internally without returning the potentially heavy JSON structure back across the WASM/FFI boundary.
```typescript
await evalInstance.evaluateOnly({
  data: string | object,
  context?: string | object,
  paths?: string[]
});
```

**`compileLogic` & `runLogic`**
Pre-compile and execute standalone JSON Logic expressions directly.
```typescript
const logicId = await evalInstance.compileLogic("{\"var\": \"user.name\"}");
const result = await evalInstance.runLogic(logicId, { data });

// Or in one step:
const directResult = await evalInstance.compileAndRunLogic({ logicStr: "...", data });
```

**`resolveLayout`**
Resolves UI layout nodes independently of core evaluation.
```typescript
await evalInstance.resolveLayout(true); // pass true to evaluate embedded layout properties
```

#### Schema Getters

Retrieve the resolved internal state of the evaluation, or query the structural properties.

**Full Schema Retrieval**
```typescript
// Full evaluated schema object
const schema = await evalInstance.getEvaluatedSchema(false);

// Schema without the heavy $params block
const cleanSchema = await evalInstance.getEvaluatedSchemaWithoutParams(false);

// Evaluated schema as raw MessagePack Uint8Array for high-performance zero-copy transfers
const msgpackBytes = await evalInstance.getEvaluatedSchemaMsgpack(false);
```

**Specific Path Retrieval**
```typescript
// Specific path from evaluated schema
const pathResult = await evalInstance.getEvaluatedSchemaByPath({ path: "#/properties/name", skipLayout: false });
const pathsResult = await evalInstance.getEvaluatedSchemaByPaths({ paths: ["#/properties/A", "#/properties/B"], skipLayout: false });

// Extract final .value from root or paths
const val = await evalInstance.getSchemaValue();
const arrVal = await evalInstance.getSchemaValueArray();
const objVal = await evalInstance.getSchemaValueObject();

// Original schema structure queries (before evaluation applied)
const origPath = await evalInstance.getSchemaByPath({ path: "#/properties/name" });
const origPaths = await evalInstance.getSchemaByPaths({ paths: ["#/properties/A", "#/properties/B"] });
```

#### Lifecycle & Caching

Manage internal evaluation memory and computation caches.

**Schema Reloading**
Hot-swap the schema without recreating the WebAssembly instance interface.
```typescript
await evalInstance.reloadSchema({ schema: newSchema, data: newData });
await evalInstance.reloadSchemaMsgpack(new Uint8Array([...]), context, data);
await evalInstance.reloadSchemaFromCache("cache_key", context, data);
```

**Evaluation Cache Management**
Manage the internal node evaluation cache.
```typescript
await evalInstance.enableCache();
await evalInstance.disableCache();
await evalInstance.clearCache();
const stats = await evalInstance.cacheStats(); // Returns entries, hits, misses
const len = await evalInstance.cacheLen();
```

## Advanced: Dynamic Imports (Review for Next.js)

For frameworks like Next.js where you might want to load WASM only on the client side:

```typescript
'use client';

import { useEffect, useState } from 'react';

export function MyComponent() {
  const [evaluator, setEvaluator] = useState(null);

  useEffect(() => {
    async function load() {
      const [ { JSONEval }, wasmModule ] = await Promise.all([
        import('@json-eval-rs/webcore'),
        import('@json-eval-rs/bundler')
      ]);

      const instance = new JSONEval({ 
        schema, 
        wasmModule 
      });
      setEvaluator(instance);
    }
    load();
    
    return () => evaluator?.free();
  }, []);
  
  // ...
}
```

## Memory Management

Since the Web implementation relies on WebAssembly (Rust), memory is managed manually to ensure performance and prevent leaks. **You must call `.free()`** when you are done with an instance.

```typescript
// Good practice
try {
  await instance.evaluate(...);
} finally {
  instance.free(); // Optional cancellation via instance.cancel() exists too
}
```

## Subform Usage

The web binding exposes the full suite of subform APIs mirroring the core:
- `validateSubform(options)`
- `evaluateDependentsSubform(options)` / `evaluateDependentsSubformString(options)`
- `resolveLayoutSubform(options)`
- `getSchemaValueSubform(...)` / `getSchemaValueArraySubform(...)` / `getSchemaValueObjectSubform(...)`
- `getEvaluatedSchemaByPathSubform(...)` / `getEvaluatedSchemaByPathsSubform(...)`
- `getSchemaByPathSubform(...)` / `getSchemaByPathsSubform(...)`
- `getSubformPaths()` / `hasSubform(path)`
