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

@maximilianslawik/tbrowser

v0.1.1

Published

Full Node.js and npm runtime for the tbrowser local browser control plane

Readme

tbrowser

Full Node.js and npm runtime for tbrowser.

This repository now includes both:

  • a typed Node client and CLI
  • a full Node control plane that launches isolated Chromium sessions in Docker

The npm package can run the server itself with tbrowser serve. It does not depend on the Rust implementation at runtime.

What it includes

  • session lifecycle API
  • navigation, eval, DOM snapshots, screenshots
  • desktop mouse and keyboard control through docker exec + xdotool
  • approvals and local policy enforcement
  • uploads, download detection, artifacts
  • tabs, network captures, traces
  • audit history and WebSocket session events
  • named profile import and export
  • bundled browser image assets for local Docker builds

Install

npm install @maximilianslawik/tbrowser

Requirements

  • Node.js 18 or newer
  • Docker daemon reachable from the local host

Build the browser image

The server expects a browser image tagged as tbrowser/browser-base:local unless you override TBROWSER_BROWSER_IMAGE.

From this repository:

npm run build:image

Run the server

tbrowser serve

Or with explicit settings:

tbrowser serve \
  --bind-addr 127.0.0.1:3000 \
  --data-dir ./storage \
  --browser-image tbrowser/browser-base:local \
  --public-host 127.0.0.1

Default API base:

http://127.0.0.1:3000

Environment variables

  • TBROWSER_BIND_ADDR Default: 127.0.0.1:3000
  • TBROWSER_DATA_DIR Default: ./storage
  • TBROWSER_DATABASE_URL Default: sqlite:${TBROWSER_DATA_DIR}/state/tbrowser.db
  • TBROWSER_BROWSER_IMAGE Default: tbrowser/browser-base:local
  • TBROWSER_PUBLIC_HOST Default: 127.0.0.1
  • TBROWSER_CLEANUP_INTERVAL_SECONDS Default: 30
  • TBROWSER_IDLE_TIMEOUT_SECONDS Default: 300
  • TBROWSER_APPROVAL_TTL_SECONDS Default: 600
  • TBROWSER_POLICY_PATH Optional JSON file for blocked hosts, approval hosts, approval-gated actions, and sensitive eval keywords

Policy file shape

{
  "blocked_hosts": ["*.internal.example"],
  "approval_hosts": ["accounts.google.com", "*.bank.example"],
  "approval_actions": ["desktop", "upload", "download", "tab_close"],
  "sensitive_eval_keywords": ["document.cookie", "navigator.clipboard"]
}

Client usage

import { TbrowserClient } from "@maximilianslawik/tbrowser";

const client = new TbrowserClient({
  baseUrl: "http://127.0.0.1:3000"
});

const session = await client.createSession({
  label: "demo",
  initial_url: "https://example.com",
  launch: {
    headless: true
  }
});

const snapshot = await client.snapshot(session.id);
console.log(snapshot.title);

Embedded server usage from code

import { createTbrowserServer } from "@maximilianslawik/tbrowser";

const server = await createTbrowserServer({
  bindAddr: "127.0.0.1:3000",
  dataDir: "./storage"
});

await server.listen();

CLI examples

tbrowser health
tbrowser policy
tbrowser sessions create --json '{"label":"demo","launch":{"headless":true}}'
tbrowser sessions navigate SESSION_ID --url https://example.com
tbrowser sessions screenshot SESSION_ID --output ./page.png
tbrowser uploads from-path SESSION_ID --selector '#upload' --path ./document.pdf
tbrowser events stream SESSION_ID

API coverage

The Node runtime exposes the same control-plane surface as the Rust repo:

  • POST /v1/sessions
  • GET /v1/sessions
  • GET /v1/sessions/{session_id}
  • DELETE /v1/sessions/{session_id}
  • GET /v1/sessions/{session_id}/live
  • POST /v1/sessions/{session_id}/navigate
  • POST /v1/sessions/{session_id}/eval
  • POST /v1/sessions/{session_id}/snapshot
  • POST /v1/sessions/{session_id}/screenshot
  • GET /v1/sessions/{session_id}/events
  • GET /v1/sessions/{session_id}/events/ws
  • GET /v1/policy
  • GET /v1/sessions/{session_id}/approvals
  • POST /v1/sessions/{session_id}/approvals
  • POST /v1/approvals/{approval_id}/decision
  • GET /v1/sessions/{session_id}/artifacts
  • GET /v1/sessions/{session_id}/artifacts/{artifact_id}
  • GET /v1/sessions/{session_id}/tabs
  • POST /v1/sessions/{session_id}/tabs
  • POST /v1/sessions/{session_id}/tabs/{tab_id}/activate
  • POST /v1/sessions/{session_id}/tabs/{tab_id}/close
  • POST /v1/sessions/{session_id}/uploads
  • POST /v1/sessions/{session_id}/downloads/wait
  • POST /v1/sessions/{session_id}/captures/network
  • POST /v1/sessions/{session_id}/captures/trace
  • POST /v1/sessions/{session_id}/desktop/mouse/move
  • POST /v1/sessions/{session_id}/desktop/mouse/click
  • POST /v1/sessions/{session_id}/desktop/mouse/drag
  • POST /v1/sessions/{session_id}/desktop/keyboard/type
  • POST /v1/sessions/{session_id}/desktop/keyboard/key
  • POST /v1/sessions/{session_id}/desktop/drag-element
  • GET /v1/profiles
  • GET /v1/profiles/{profile_id}
  • POST /v1/profiles/import
  • POST /v1/profiles/{profile_id}/export

Development

npm install
npm test
npm run build:image

Publish

The package is structured for npm publish:

npm publish

If you want a scoped package name, change the name field in package.json before publishing.