npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sessionat/sdk

v0.1.0

Published

TypeScript SDK to script and automate the Sessionat browser over its built-in MCP server — read your workspaces and 100% local visit analytics, drive tabs, and automate any page from Node. Requires the free Sessionat browser (https://sessionat.com).

Readme

@sessionat/sdk

Script and automate the Sessionat browser from Node & TypeScript.

Sessionat is a free, open-source, privacy-first browser with a built-in MCP server — so AI assistants and your own code can drive it. This SDK is the typed, ergonomic client for that server: read your workspaces and 100%-local visit analytics, open and control tabs, and automate any page — all over a local loopback connection that never leaves your machine.

🧩 Requires the Sessionat browser. Download the free app at sessionat.com, then enable the MCP server in chrome://sessionat-mcp/.

import { Sessionat } from "@sessionat/sdk";

const browser = await Sessionat.connect();               // zero-config auto-discovery

// Your private, local analytics — no approval needed:
const top = await browser.analytics.topSites({ range: "7d", orderBy: "active_seconds" });
console.log(top.top_sites);                               // [{ host, visit_count, active_seconds, category }]

// Drive the browser (one-time approval in chrome://sessionat-mcp/):
await browser.tabs.open("https://news.ycombinator.com");
await browser.page.waitFor({ text: "Hacker News" });
const shot = await browser.page.screenshot();             // { data: base64, mimeType: "image/png" }

Install

npm i @sessionat/sdk
# or the unscoped alias:  npm i sessionat-sdk
  • Zero runtime dependencies. Uses the built-in fetch (Node 18+).
  • Ships ESM + CommonJS + full TypeScript types.

Why

Sessionat is built around three pillars — Arc-style workspaces, a local private analytics dashboard, and a built-in MCP server. The MCP server already lets Claude Desktop, Cursor, Codex, Claude Code, Windsurf and VS Code connect with one click. This SDK gives you the same surface from code:

  • 📊 Query your own data — top sites, focus categories, time-of-day buckets, full visit history — all stored locally, nothing uploaded.
  • 🗂️ Manage workspaces — list, inspect, and create Arc-style workspaces.
  • 🤖 Automate the live browser — open/close/focus tabs, navigate, read page text, click, type, scroll, wait, screenshot, even cross-origin iframes and canvas apps.

Learn more about the browser at sessionat.com.

How connect() finds your browser

When Sessionat is running with MCP enabled it writes a small discovery file (mcp.json) into its profile directory containing the loopback port and a bearer token. Sessionat.connect() finds it automatically — scanning the default profile locations and health-probing each candidate so it picks the live one.

You can also be explicit:

// Explicit endpoint (copy from chrome://sessionat-mcp/ → "Other" tab):
await Sessionat.connect({ url: "http://127.0.0.1:54321/mcp", token: "…" });

// Point at a specific profile or discovery file:
await Sessionat.connect({ profileDir: "/path/to/Sessionat/Default" });
await Sessionat.connect({ discoveryFile: "/path/to/mcp.json" });

Or via environment variables (great for CI / scripts):

| Variable | Purpose | |---|---| | SESSIONAT_MCP_URL + SESSIONAT_MCP_TOKEN | Use this exact endpoint, skip discovery. | | SESSIONAT_MCP_DISCOVERY | Path to an mcp.json discovery file. | | SESSIONAT_PROFILE_DIR | A profile dir; <dir>/mcp.json is read. |

Write tools need one-time approval

Reading analytics is open. But every write / automation tool (opening tabs, clicking, typing, even listing open tabs) is gated behind a one-time, per-client approval — Sessionat's deliberate guard against prompt-injection. The first such call throws:

import { SessionatWriteApprovalError } from "@sessionat/sdk";

try {
  await browser.tabs.open("https://example.com");
} catch (err) {
  if (err instanceof SessionatWriteApprovalError) {
    // → Open chrome://sessionat-mcp/ in Sessionat, enable write tools, retry.
    console.error(err.message);
  }
}

API

Connection: Sessionat.connect(options?)Sessionat. Properties: serverInfo, url, port, source.

browser.workspaces

| Method | Tool | Notes | |---|---|---| | list() | sessionat_list_workspaces | all workspaces + active id | | active() | sessionat_get_active_workspace | active workspace + its tabs | | get(workspaceId) | sessionat_get_workspace | one workspace by id | | create({ name, color?, icon? }) | sessionat_create_workspace | write |

browser.analytics

| Method | Tool | |---|---| | topSites({ range?, workspaceId?, limit?, orderBy? }) | sessionat_get_top_sites | | categories({ range?, workspaceId? }) | sessionat_get_category_breakdown | | buckets({ bucket, range?, workspaceId? }) | sessionat_get_visit_buckets |

browser.visits

| Method | Tool | |---|---| | list({ range?, workspaceId?, limit? }) | sessionat_get_visits | | search(query, { range?, workspaceId?, limit? }) | sessionat_search_visits | | forHost(host, { range?, workspaceId?, limit? }) | sessionat_get_visits_for_host |

range is "today" | "7d" | "30d" | "all". orderBy is "visits" | "active_seconds". bucket is "hour" | "day_of_week" | "day".

browser.tabs (all write-gated)

| Method | Tool | |---|---| | list() | sessionat_list_open_tabs | | active() | sessionat_get_active_tab | | open(url, { background? }) | sessionat_open_url | | focus(index) | sessionat_focus_tab | | close(index) | sessionat_close_tab |

browser.page (all write-gated)

| Method | Tool | |---|---| | navigate(url) | sessionat_navigate_active_tab | | text({ maxChars?, rootSelector?, iframeSelector?, frameUrlMatch? }) | sessionat_get_page_text | | click({ selector?, text?, textExact?, frameUrlMatch? }) | sessionat_click | | type({ selector?, fieldLabel?, text, submit?, frameUrlMatch? }) | sessionat_type | | waitFor({ selector?, text?, textExact?, timeoutMs? }) | sessionat_wait_for | | scroll({ selector?, dx?, dy?, position? }) | sessionat_scroll | | outline({ limit?, rootSelector?, frameUrlMatch? }) | sessionat_get_dom_outline | | screenshot({ maxWidth? }){ data, mimeType } | sessionat_screenshot | | frames() | sessionat_list_frames | | pressKey(key, { modifiers? }) | sessionat_press_key | | typeKeys(text) | sessionat_press_key (text mode) |

click and outline pierce shadow DOM (Reddit, Slack, Polymer). frameUrlMatch drives cross-origin iframes (Stripe, OAuth, embeds). typeKeys sends real trusted key events for canvas apps (Google Docs, Figma).

Low-level escape hatch

const tools = await browser.listTools();                  // raw tool definitions
const result = await browser.callTool("sessionat_get_top_sites", { range: "30d" });
const raw = await browser.request("ping");                // any JSON-RPC method

Errors

All extend SessionatError:

  • SessionatConnectionError — browser not found / unreachable.
  • SessionatAuthError — bearer token rejected (HTTP 401).
  • SessionatWriteApprovalError — write tool used before approval (.toolName, .clientId).
  • SessionatToolError — a tool ran but returned an error (.toolName).
  • SessionatRpcError — JSON-RPC protocol error (.code, .data).

Examples

See examples/: quickstart.mjs (read analytics) and automate-search.mjs (drive a page).

Privacy

The connection is loopback-only (127.0.0.1), bearer-token authenticated, and your visit data never leaves your device — that's a core product guarantee of Sessionat. This SDK makes no outbound network calls of its own beyond the local browser.

Links

License

MIT © Sessionat