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

@haatlabs-core/extension-kit

v0.10.0

Published

The browser side of an extension's panel: the active tab, page reads, downloads, sign-in keys.

Readme

@haatlabs-core/extension-kit

The browser side of an extension's panel (Manifest V3): the PanelEnv of @haatlabs-core/extension-ui for a Chrome or Edge side panel, the service worker's setup, and the key an app's own connect page hands the extension.

Install

pnpm add @haatlabs-core/extension-kit

Use

  • createChromePanelEnv(): the active tab (once the person clicked the icon there, or allowed every site), tab changes in the panel's own window, downloads (a file made in parts is saved as one), JSON read from inside the page as the page would, and the page's scripts and globals.
  • openSidePanelOnIconClick(), in the service worker: the toolbar icon opens the side panel.
  • Sign-in through the app's own connect page: startConnect(webOrigin) opens <webOrigin>/connect/extension?extension=<id>; listenForConnections({ <app>: <webOrigin> }) in the service worker keeps the key that page sends (<app>.connected), only from that origin; createAuthStore(app) reads, keeps and forgets it in local storage (never synced).

For an extension of an app with its own backend (not built on the platform):

  • fillFields(tabId, [{ selector, value }]) fills a page's form in the page's own world, so React and Vue forms keep the values (a <select> by its value or its text), and returns { filled, missing }: show what was missing, never skip it. copyText(text) copies.
  • SiteAdapter: one site's form as data (matches as Chrome match patterns, the anchor field, and fields(data, page)); matchAdapter(url, adapters) picks the page's.
  • installFillButton({ adapters, label, onFill }), in a content script: a button beside the form's first field once it appears.
  • startOAuthPkce({ authorizeUrl, tokenUrl, clientId, scopes }) signs in through chrome.identity with OAuth 2 and PKCE (S256, state checked) and returns { accessToken, refreshToken, expiresAt }; refreshOAuth(grant, tokenUrl, clientId) renews it in its last minute. createAuthStore keeps either kind of grant.

Chrome, Edge, Firefox and Safari from one code base:

  • browserName() (chromium, firefox, safari, from the scheme of the extension's own pages) and extensionApi() (browser where there is one, else chrome). createChromePanelEnv works in each: Firefox and Safari answer chrome.* too.
  • openPanelOnIconClick(), in the background script: Chromium's side panel, Firefox's sidebar; on Safari the panel is the action's popup.
  • manifestFor(browser, base, { geckoId }) writes each browser's manifest from one Chromium base: Firefox gets sidebar_action, a background script and browser_specific_settings; Safari a popup and no identity permission.
  • startOAuthPkce signs in with chrome.identity or browser.identity; on Safari, which has none, through a tab to the app's own page (safariRedirectUri), which hands the answer back with browser.runtime.sendMessage.

The manifest needs the sidePanel, scripting, downloads, storage and activeTab permissions, optional_host_permissions: ["https://*/*"], and the app's web origin in externally_connectable.

The package is for the browser only: its code runs in an extension, through a bundler.