npm package: @hashtree/worker
Description: Modular browser worker for hashtree blob caching, tree-root state, and Blossom connectivity
Author: Martti Malmi
Latest version: 0.1.25

# @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

```bash
npm install @hashtree/worker
```

## Usage

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

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

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

## Iris Worker Client

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

```typescript
import { IrisWorkerClient } from '@hashtree/worker/iris-client';
import HashtreeWorker from '@hashtree/worker/iris-entry?worker';

const client = new IrisWorkerClient(HashtreeWorker, {
  storeName: 'iris-sites-worker',
  relays: ['wss://relay.damus.io'],
  blossomServers: [{ url: 'https://upload.iris.to', 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);
});
```

## Iris-Compatible Runtime Defaults

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

```typescript
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.iris.to', read: false, write: true },
  { url: 'https://cdn.iris.to', 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:

```typescript
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 Iris/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.

## 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 Iris child webviews are active at once, without falling back to a single global port.

## Exports

- `@hashtree/worker` — `createHtreeRuntime`, `resolveRuntimeEndpoints`, and `HashtreeWorkerClient`
- `@hashtree/worker/iris-client` — `IrisWorkerClient` plus Iris-specific tree-root metadata types
- `@hashtree/worker/worker` — `attachHashtreeWorker(...)` for embedding the worker protocol into a custom worker
- `@hashtree/worker/p2p` — `WebRTCController` / `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