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

@solarisdk/browser

v0.5.4

Published

Official client SDK for Solari Browser.

Readme

@solarisdk/browser

Official client SDK for Solari Browser — managed, stealth-hardened browsers as an API.

Feature coverage across all five languages is on the SDK feature matrix.

Install

npm install @solarisdk/browser

Quickstart

import { Solari } from "@solarisdk/browser";

const solari = new Solari({
    apiKey: process.env.SOLARI_API_KEY!,
    // region: "us-west",  // default — additional regions coming soon
});

const browser = await solari.launch({ stealth: true });
const page = await browser.newPage();
await page.goto("https://example.com");
console.log(await page.title());
await browser.close();

Or with explicit resource management (compiled TypeScript 5.2+, or uncompiled on Node 24+; Node 22 rejects the syntax):

await using browser = await solari.launch({ stealth: true });
const page = await browser.newPage();
await page.goto("https://example.com");

Sessions

Drive a session yourself instead of using launch():

const session = await solari.sessions.create({ stealth: true });
// connect via Playwright wire protocol
import { chromium } from "patchright-core";
const browser = await chromium.connect(session.wsEndpoint);
// ...
await browser.close();
await solari.sessions.releaseAndWait(session.id);

Or via raw CDP (Puppeteer, browser-use, playwright-core):

const session = await solari.sessions.create();
const browser = await chromium.connectOverCDP(session.cdpEndpoint);

Get and list sessions

const view = await solari.sessions.get(session.id); // status, kind, userMetadata, endpoints while active
let page = await solari.sessions.list({ limit: 50, metadata: { job: "nightly-42" } });
// page.sessions, page.nextCursor (absent on the last page)

list never returns the websocket endpoints (they are bearer capabilities): call get for a single session's. Pass page.nextCursor as cursor for the next page.

Every REST error carries the gateway's code when it sends one, so you can branch on it whichever call failed: e.code === "ReplayPending" (a replay still uploading; wait and call again), "SessionNotFound", "InvalidSessionId", "PlanLimitExceeded" and so on.

Timeout, keep-alive and metadata

const session = await solari.sessions.create({
    sessionTimeoutMs: 600_000, // end earlier than the plan maximum, in ms (at least 60 000)
    keepAlive: true,           // keep it if the client drops: held until sessionTimeoutMs after creation (1 h if unset) or release
    userMetadata: { job: "nightly-42" }, // stored with the session
});

Every duration option is in milliseconds. sessionTimeoutMs is rounded up to whole seconds for the gateway (1001 ms is 2 s); the gateway refuses anything under 60 s; zero or unset leaves the plan maximum, and a negative, NaN, Infinity or fractional value throws before any request. launch() accepts the same options.

Edit a profile

solari.profiles.edit(id) opens the profile editor, where a person signs in once and the result is saved into the profile. It returns a handle; give its url to whoever should sign in, or open it yourself.

const editor = await solari.profiles.edit("prof_123", { reason: "Sign in to Acme" });
console.log(editor.url); // open this in a browser

await editor.waitForSave({ timeoutMs: 10 * 60_000 }); // the person clicks Save in the editor page
// or drive it from code once they are done:
await editor.saveAndClose(); // save and close the editor
await editor.exit();         // close it WITHOUT saving
console.log(await editor.status());

The link works for 30 minutes and the editor starts when the person clicks "Open editor" on the page. After that the editor stops by itself and these calls fail with a clear 404 (link expired) or 409 (editor not running). There is no save-and-keep-editing: saveAndClose() saves and closes.

Regions

Solari runs in us-west (N. California) today, with additional regions coming soon. Sessions, replays, and profile storage are colocated with the region you pick.

const solari = new Solari({ apiKey, region: "us-west" });

For staging or self-hosted gateways, pass baseUrl instead of region.

Managed proxies

Proxy bandwidth is billed per GB, and pages heavy in video and images can cost tens of megabytes per session. blockHeavy (off by default) skips them:

await solari.launch({
    stealth: true,
    proxy: "us",
    blockHeavy: true, // video/audio + images over 100 KB; or { fonts: true, imageMaxBytes: 50_000 }
});

Blocked requests fail inside the browser, so nothing is fetched and nothing leaves through a different route; the page sees an ordinary failed load and the blocked image or video does not appear. Images that declare no size, and requests made by service workers or cross-origin iframes, are not covered. Replays still play: they load media from the original site.

await solari.launch({
    stealth: true,
    proxy: { country: "us", tier: "mobile" },
});

For targets whose stealth posture is unknown a priori, proxy: "smart" runs an escalation ladder (rotating residential → direct → mobile → fresh residential → residential GB) and swaps the egress in-place when a block page is detected mid-session — no client-side retry required.

await solari.launch({ stealth: true, proxy: "smart" });

See the Solari docs for the full proxy, stealth, captcha, and profile reference.

Errors

import { SolariError } from "@solarisdk/browser";

try {
    await solari.sessions.create({ stealth: true });
} catch (err) {
    if (err instanceof SolariError && err.code === "FeatureRequiresPlan") {
        // ...
    }
}

License

MIT