Node.js SDK

The official Node.js SDK for Plasmate, with full TypeScript types and SOM query helpers.

Installation

npm install plasmate

Requires Node.js 18+ and the plasmate binary on your PATH.

Quick Start

import { Plasmate } from 'plasmate';

const client = new Plasmate();

// Fetch a page and get SOM
const som = await client.som('https://example.com');
console.log(som.title);       // "Example Domain"
console.log(som.regions);     // semantic regions
console.log(som.meta);        // compression stats

client.close();

TypeScript Types

`Som`

The top-level SOM document.

interface Som {
  som_version: string;
  url: string;
  title: string;
  lang: string;
  regions: SomRegion[];
  meta: SomMeta;
  structured_data?: StructuredData;
}

`SomRegion`

A semantic region of the page (navigation, main content, sidebar, etc.).

interface SomRegion {
  id: string;
  role: RegionRole;   // 'navigation' | 'main' | 'aside' | 'header' | 'footer' | 'form' | 'dialog' | 'content'
  label?: string;
  action?: string;
  method?: string;
  elements: SomElement[];
}

`SomElement`

An individual element within a region.

interface SomElement {
  id: string;
  role: ElementRole;  // 'link' | 'button' | 'text_input' | 'textarea' | 'select' | 'checkbox' | 'radio' | 'heading' | 'image' | 'list' | 'table' | 'paragraph' | 'section' | 'separator'
  text?: string;
  label?: string;
  actions?: ElementAction[];
  attrs?: SomElementAttrs;
  children?: SomElement[];
  hints?: SemanticHint[];
}

`SomMeta`

Compression and element statistics.

interface SomMeta {
  html_bytes: number;
  som_bytes: number;
  element_count: number;
  interactive_count: number;
}

Query Helpers

All query helpers accept a Som object and return matching elements or regions.

`findByRole(som, role)`

Find all regions matching a given role.

import { findByRole } from 'plasmate';

const navRegions = findByRole(som, 'navigation');

`findById(som, id)`

Find a single element by its stable ID.

import { findById } from 'plasmate';

const el = findById(som, 'login-btn');
if (el) console.log(el.text);

`findByTag(som, tag)`

Find elements matching a tag/role string.

import { findByTag } from 'plasmate';

const links = findByTag(som, 'link');

`findInteractive(som)`

Return all interactive elements (links, buttons, inputs, selects, textareas, checkboxes, radios).

import { findInteractive } from 'plasmate';

const interactive = findInteractive(som);
console.log(`${interactive.length} interactive elements`);

`getActionPlan(som)`

Return compact action targets with stable ids, deterministic cache_key values, labels, action lists, and availability state.

import { getActionPlan } from 'plasmate';

const availableTargets = getActionPlan(som).filter((target) => target.enabled);

`getActionPlanCacheKey(item)`

Return the same deterministic cache key used by getActionPlan() for a compact target.

import { getActionPlanCacheKey } from 'plasmate';

const cacheKey = getActionPlanCacheKey(target);

`getActionPlanIndex(som, options)`

Return compact action targets indexed by replay ids and grouped by role/action. Use this when an agent needs a small action menu instead of the full SOM.

import { getActionPlanIndex } from 'plasmate';

const index = getActionPlanIndex(som, { enabledOnly: true });
const buttons = index.byRole.button ?? [];
const clickTargets = index.byAction.click ?? [];

`findActionTargetsByRole(som, role, options)`

Return compact action targets for one SOM role without scanning the full plan.

import { findActionTargetsByRole } from 'plasmate';

const buttons = findActionTargetsByRole(som, 'button', { enabledOnly: true });

`findActionTargetsByAction(som, action, options)`

Return compact action targets exposing one action.

import { findActionTargetsByAction } from 'plasmate';

const clicks = findActionTargetsByAction(som, 'click', { enabledOnly: true });

`findByText(som, text)`

Find elements whose text content contains the given string (case-insensitive).

import { findByText } from 'plasmate';

const matches = findByText(som, 'Sign in');

`flatElements(som)`

Flatten all elements across all regions into a single array.

import { flatElements } from 'plasmate';

const all = flatElements(som);

`getTokenEstimate(som)`

Estimate the LLM token count for the SOM (heuristic: ~4 bytes per token).

import { getTokenEstimate } from 'plasmate';

const tokens = getTokenEstimate(som);
console.log(`~${tokens} tokens`);

Client API

Constructor

const client = new Plasmate({
  binary: 'plasmate',   // path to plasmate binary (default: 'plasmate')
  timeout: 30000,       // timeout in ms (default: 30000)
});

Stateless Methods

// Fetch a page and return SOM
const som = await client.som(url, options?);

// Alias for som()
const som = await client.fetchPage(url, options?);

// Extract plain text from a page
const text = await client.extractText(url, options?);

Stateful Sessions

// Open a persistent page session
const { sessionId, som } = await client.openPage(url);

// Execute JavaScript in the session
const result = await client.evaluate(sessionId, 'document.title');

// Click an element and get updated SOM
const updatedSom = await client.click(sessionId, 'login-btn');

// Close the session
await client.closePage(sessionId);

Cleanup

client.close();

The client communicates with the plasmate mcp subprocess over JSON-RPC 2.0 on stdio. It auto-starts the process on first call.