---
title: 'Web & NodeJS'
description: "Paket @json-eval-rs/webcore menyediakan API tingkat tinggi yang seragam untuk lingkungan Browser (WASM) dan NodeJS. Paket ini akan memuat backend yang sesuai secara otomatis."
navigation:
  icon: 'i-simple-icons-nodedotjs'
seo:
  title: 'Web & NodeJS'
  description: "Paket @json-eval-rs/webcore menyediakan API tingkat tinggi yang seragam untuk lingkungan Browser (WASM) dan NodeJS. Paket ini akan memuat backend yang sesuai secara otomatis."
---

## Instalasi

### Untuk Web (Bundler: Vite, Webpack, dsb.)

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

-   `@json-eval-rs/webcore`: API TS tingkat tinggi.
-   `@json-eval-rs/bundler`: Target kompilasi WASM untuk bundler.

### Untuk Web (Vanilla JS / Script tag browser)

Jika kamu tidak menggunakan bundler (atau butuh modul native ECMA script yang kompatibel dengan browser):

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

-   `@json-eval-rs/vanilla`: Target kompilasi WASM untuk dijalankan langsung di browser.

### Untuk NodeJS

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

-   `@json-eval-rs/node`: Binding NodeJS (lewat N-API/WASM).

## Mulai Cepat (Node.js)

Penggunaan di Node.js mengandalkan paket `@json-eval-rs/node` untuk mendaftarkan binding native secara otomatis.

```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();
```

## Mulai Cepat (Web Bundler)

Untuk framework seperti Vite, Webpack, Next.js, dan NuxtJS, kamu perlu mengimpor modul WASM dan menyertakannya saat inisialisasi.

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

// 1. Inisialisasi
// Menyertakan wasmModule secara eksplisit memudahkan bundler untuk memuat WASM dengan benar
const evalInstance = new JSONEval({
  schema: mySchema,
  wasmModule
});

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

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

## Mulai Cepat (Web Vanilla)

Untuk lingkungan browser standar tanpa bundler, target vanilla mengekspor paket WASM yang ramah dengan modul ES.

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

// Inisialisasi caranya persis sama dengan metode bundler:
const evalInstance = new JSONEval({
  schema: mySchema,
  wasmModule
});

// ... Evaluasi dan hapus penggunaan memori (free)
evalInstance.free();
```

## Referensi API

### Kelas `JSONEval`

#### Constructor

```typescript
new JSONEval(options: {
  schema: SchemaObject | string;
  context?: object | string;
  data?: object | string;
  wasmModule?: any; // Wajib diisi untuk web bundler
})
```

#### `evaluate`

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

#### `validate`

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

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

#### `evaluateSubform`

```typescript
await evaluateSubform(options: {
  subformPath: string; // misal: "#/items"
  data: object | string;
  paths?: string[]; // Jalur selektif di dalam item subform
})
```

#### `evaluateDependents`

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

#### Metode Lanjutan

**`validatePaths`**
Validasi terarah hanya untuk jalur tertentu. Berguna jika kamu hanya perlu mengecek error pada satu atau beberapa kolom saja.
```typescript
const result = await evalInstance.validatePaths({
  data: string | object,
  context?: string | object,
  paths: string[]
});
```
*(Juga tersedia: `validatePathsOnly`, yang mengecek aturan validasi tapi melewati pembuatan objek schema hasil evaluasi penuh di internal)*

**`evaluateOnly`**
Mengevaluasi status schema secara internal tanpa mengembalikan struktur JSON yang mungkin berat melewati jalur WASM/FFI.
```typescript
await evalInstance.evaluateOnly({
  data: string | object,
  context?: string | object,
  paths?: string[]
});
```

**`compileLogic` & `runLogic`**
Menyusun (compile) dan menjalankan ekspresi JSON Logic mandiri secara langsung.
```typescript
const logicId = await evalInstance.compileLogic("{\"var\": \"user.name\"}");
const result = await evalInstance.runLogic(logicId, { data });

// Atau dalam satu langkah:
const directResult = await evalInstance.compileAndRunLogic({ logicStr: "...", data });
```

**`resolveLayout`**
Menyelesaikan node layout UI secara terpisah dari evaluasi core.
```typescript
await evalInstance.resolveLayout(true); // berikan true untuk mengevaluasi properti layout yang tertanam
```

#### Pengambilan Data Schema

Mengambil status internal evaluasi yang sudah diselesaikan, atau menanyakan properti struktural.

**Ambil Schema Penuh**
```typescript
// Objek schema hasil evaluasi penuh
const schema = await evalInstance.getEvaluatedSchema(false);

// Schema tanpa blok $params yang berat
const cleanSchema = await evalInstance.getEvaluatedSchemaWithoutParams(false);

// Schema hasil evaluasi dalam bentuk raw MessagePack Uint8Array untuk transfer performa tinggi tanpa kopi
const msgpackBytes = await evalInstance.getEvaluatedSchemaMsgpack(false);
```

**Ambil Jalur Spesifik**
```typescript
// Jalur spesifik dari schema hasil evaluasi
const pathResult = await evalInstance.getEvaluatedSchemaByPath({ path: "#/properties/name", skipLayout: false });
const pathsResult = await evalInstance.getEvaluatedSchemaByPaths({ paths: ["#/properties/A", "#/properties/B"], skipLayout: false });

// Mengambil hasil akhir .value dari root atau jalur
const val = await evalInstance.getSchemaValue();
const arrVal = await evalInstance.getSchemaValueArray();
const objVal = await evalInstance.getSchemaValueObject();

// Menanyakan struktur schema asli (sebelum evaluasi dijalankan)
const origPath = await evalInstance.getSchemaByPath({ path: "#/properties/name" });
const origPaths = await evalInstance.getSchemaByPaths({ paths: ["#/properties/A", "#/properties/B"] });
```

#### Siklus Hidup & Caching

Mengelola memori evaluasi internal dan cache perhitungan.

**Memuat Ulang Schema**
Mengganti schema tanpa perlu membuat ulang instance WebAssembly.
```typescript
await evalInstance.reloadSchema({ schema: newSchema, data: newData });
await evalInstance.reloadSchemaMsgpack(new Uint8Array([...]), context, data);
await evalInstance.reloadSchemaFromCache("cache_key", context, data);
```

**Manajemen Cache Evaluasi**
Mengelola cache evaluasi node internal.
```typescript
await evalInstance.enableCache();
await evalInstance.disableCache();
await evalInstance.clearCache();
const stats = await evalInstance.cacheStats(); // Mengembalikan entri, hit, miss
const len = await evalInstance.cacheLen();
```

## Lanjutan: Impor Dinamis (Review untuk Next.js)

Untuk framework seperti Next.js di mana kamu ingin memuat WASM hanya di sisi klien:

```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();
  }, []);
  
  // ...
}
```

## Manajemen Memori

Karena implementasi Web mengandalkan WebAssembly (Rust), memori dikelola secara manual untuk memastikan performa dan mencegah kebocoran (leak). **Kamu wajib memanggil `.free()`** jika sudah selesai menggunakan instance.

```typescript
// Praktik yang baik
try {
  await instance.evaluate(...);
} finally {
  instance.free(); // Ada juga opsi pembatalan lewat instance.cancel()
}
```

## Penggunaan Subform

Binding web menyediakan rangkaian lengkap API subform yang sama dengan corenya:
- `validateSubform(options)`
- `evaluateDependentsSubform(options)` / `evaluateDependentsSubformString(options)`
- `resolveLayoutSubform(options)`
- `getSchemaValueSubform(...)` / `getSchemaValueArraySubform(...)` / `getSchemaValueObjectSubform(...)`
- `getEvaluatedSchemaByPathSubform(...)` / `getEvaluatedSchemaByPathsSubform(...)`
- `getSchemaByPathSubform(...)` / `getSchemaByPathsSubform(...)`
- `getSubformPaths()` / `hasSubform(path)`
