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

@hashtree/worker

v0.2.16

Published

Modular browser worker for hashtree blob caching, tree-root state, and Blossom connectivity

Readme

@hashtree/worker

Modular browser worker for hashtree blob caching and Blossom connectivity.

Runs hashtree storage operations in a Web Worker to keep the main thread free. Handles IndexedDB caching, Blossom server uploads/downloads, connectivity probing, and WebRTC P2P data exchange.

Install

npm install @hashtree/worker

Usage

import { HashtreeWorkerClient } from '@hashtree/worker';
import HashtreeWorker from './workers/hashtree.worker.ts?worker';

const client = new HashtreeWorkerClient(HashtreeWorker, {
  blossomServers: [{ url: 'https://upload.example', read: true, write: true }],
});
await client.init();

// Store and retrieve blobs
const { hashHex } = await client.putBlob(data);
const { data: blob } = await client.getBlob(hashHex);

Plain Worker + App-Owned Nostr

For simple apps, keep ordinary Nostr reads in app code and let the worker focus on storage, Blossom, and mesh transport:

import { HashtreeWorkerClient } from '@hashtree/worker';
import { ManagedWebRTCMeshHost } from '@hashtree/worker/p2p';
import { SimplePool } from 'nostr-tools/pool';

const client = new HashtreeWorkerClient(HashtreeWorker, {
  storeName: 'demo-worker',
});
await client.init();

const meshHost = new ManagedWebRTCMeshHost();
meshHost.attachWorkerClient(client);

const pool = new SimplePool();
const profileSub = pool.subscribeMany(
  ['wss://relay.damus.io'],
  [{ kinds: [0], authors: ['pubkey-hex'] }],
  {
    onevent(event) {
      console.log('profile metadata', event.content);
    },
  },
);

That split keeps HashtreeWorkerClient reusable for apps that only need blob/media transport, while still allowing each app to use nostr-tools or another thin client for profiles, follows, search, or other product-specific Nostr queries.

Relay Worker Client

If you are using @hashtree/worker/relay-entry?worker and need relay-backed tree-root metadata or subscription calls, use the dedicated relay wrapper:

import { RelayWorkerClient } from '@hashtree/worker/relay-client';
import HashtreeWorker from '@hashtree/worker/relay-entry?worker';

const client = new RelayWorkerClient(HashtreeWorker, {
  storeName: 'demo-sites-worker',
  relays: ['wss://relay.damus.io'],
  blossomServers: [{ url: 'https://upload.example', read: false, write: true }],
  pubkey: '336f319763657d6b0e65a5b5876719e8c8dcdcf9396852be71ee26b73368b29b',
});

await client.init();
const root = await client.getTreeRootInfo('npub1example', 'sites/example');
const stop = client.onTreeRootUpdate((update) => {
  console.log(update.treeName, update.visibility);
});

Browser Runtime Defaults

When the app runs inside Iris or another shell that injects window.__HTREE_SERVER_URL__ (or the launch URL carries htree_server), the main app-facing API should be createHtreeRuntime(...):

import {
  HashtreeWorkerClient,
  createHtreeRuntime,
} from '@hashtree/worker';
import HashtreeWorker from './workers/hashtree.worker.ts?worker';

const DEFAULT_RELAYS = [
  'wss://relay.damus.io',
  'wss://relay.primal.net',
];

const DEFAULT_BLOSSOM_SERVERS = [
  { url: 'https://upload.example', read: false, write: true },
  { url: 'https://cdn.example', read: true, write: false },
];

const runtime = createHtreeRuntime({
  appId: 'my-app',
  relays: DEFAULT_RELAYS,
  blossomServers: DEFAULT_BLOSSOM_SERVERS,
});

const workerClient = new HashtreeWorkerClient(HashtreeWorker, {
  ...runtime.getWorkerConfig({
    storeName: 'my-app-worker',
  }),
});

const mediaUrl = runtime.urls.media('htree://nhash1example/video.mp4', {
  clientScoped: true,
  mimeType: 'video/mp4',
});

await runtime.media.ensureReady({
  registerMediaPort: (port) => workerClient.registerMediaPort(port),
});

Embedding In A Custom Worker

If you already have your own worker and do not want @hashtree/worker to own the whole worker entrypoint, attach the protocol handler yourself:

import { attachHashtreeWorker } from '@hashtree/worker/worker';

attachHashtreeWorker(self);

self.addEventListener('message', (event) => {
  if (event.data?.type === 'my-custom-message') {
    // Your own worker logic.
  }
});

If you want stricter isolation, attach it to a dedicated MessagePort instead of self. That lets a larger worker multiplex hashtree traffic without sharing one global message channel.

Behavior:

  • In plain web mode, runtime.endpoints keeps your configured public relays and Blossom servers.
  • In native child runtimes, runtime.endpoints and runtime.getWorkerConfig() switch transport defaults to the local daemon endpoints.
  • runtime.urls.media(...) handles /htree/... URL generation plus the per-client htree_c and optional htree_t query params.
  • runtime.media.ensureReady(...) handles the common page-side service-worker/media-port handshake.

Transport Notes

  • If you expect media or files to keep working through the worker, daemon, or WebRTC peers, app-facing URLs should stay in htree://... or /htree/... form. Raw https:// Blossom URLs bypass the runtime routing and will fail when a client intentionally has no direct Blossom access.
  • Mesh reads should be treated as liveness-based, not fixed-timeout-based. Slow peers are normal on cold paths; callers should hedge to more peers instead of converting a slow in-flight read into a synthetic not-found.
  • After bytes or fragments start flowing, prefer idle/progress-based expiry over total wall-clock deadlines. That keeps large media transfers alive without giving malicious peers an unlimited pin.
  • For realistic verification, test cold direct navigation with requester-side Blossom disabled and assert that artwork/audio loads from /htree/... without any fallback requests to default Blossom servers.

Service Worker Client Keys

If your service worker intercepts /htree/... media requests and forwards them to a worker over MessagePort, use a stable per-tab client key:

  • createHtreeRuntime(...) generates it once per tab/webview.
  • runtime.urls.media(..., { clientScoped: true }) appends it as the htree_c query param.
  • runtime.media.ensureReady(...) sends the same key in REGISTER_WORKER_PORT and PING_WORKER_PORT.

That lets the service worker map fetches back to the correct worker port when multiple tabs or isolated child webviews are active at once, without falling back to a single global port.

Exports

  • @hashtree/workercreateHtreeRuntime, resolveRuntimeEndpoints, and HashtreeWorkerClient
  • @hashtree/worker/relay-clientRelayWorkerClient plus relay-backed tree-root metadata types
  • @hashtree/worker/workerattachHashtreeWorker(...) for embedding the worker protocol into a custom worker
  • @hashtree/worker/p2pWebRTCController / WebRTCProxy for P2P data channel management
  • @hashtree/worker/entry — Worker entry point
  • @hashtree/worker/protocol — Shared message types between main thread and worker

License

MIT