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

@zerogpu/browser-extension-sdk

v0.4.0

Published

ZeroGPU device-side SLM runtime SDK for browsers and Chrome (MV3) extensions

Readme

ZeroGPU Browser SDK

Device-side JavaScript SDK that downloads a small language model (SLM), registers the device with the ZeroGPU orchestrator, opens a WebSocket for tasks, and executes on-device summarization.

Building a Chrome extension?

Chrome Manifest V3 forbids remotely-hosted code, so the <script>/loader path below can't be used. Instead, install the package and vendor the runtime into your extension:

npm install @zerogpu/browser-extension-sdk
npx zerogpu init      # vendors the runtime + scaffolds the offscreen glue

See the full Chrome Extension developer guide (install, validate, and keep the SDK up to date).

Installation

npm install

Build

npm run build

The build produces:

  • ESM (dist/zerogpu-browser-sdk.esm.js) and CJS (dist/zerogpu-browser-sdk.cjs) bundles for npm consumers.
  • A UMD bundle (dist/zerogpu-browser-sdk.umd.js) plus an immutable, content-hashed copy under dist/v/ for CDN distribution.
  • dist/loader.js — the stable bootstrap apps embed (see UMD via <script>).
  • dist/manifest.json — points the loader at the current hashed core bundle and records the build version.

Tests

npm run test

Lint

npm run lint

Usage

ESM

import { initZeroGpuSdk } from '@zerogpu/browser-extension-sdk';

await initZeroGpuSdk({
  // Optional Telegram user ID or custom app user ID
  appUserId: 'telegram-user-1234',

  // Sent as header: x-edge-operator-key
  edgeOperatorKey: 'your-edge-operator-key',

  // Override default settings
  overrides: {
    orchestrator: {
      // Each deployment bakes in its own orchestrator at build time
      // (develop/staging/production). Override only for internal testing.
      baseUrl: 'https://devices.zerogpu.ai'
    },
    telemetry: {
      // Enable/disable detailed console logs (redacted: ids/sizes/timings only)
      enableConsoleLogs: true,
      // Request geolocation permission (default: false)
      locationData: true
    }
  }
});

UMD via <script> (always-latest loader)

Embed the loader URL — dist/loader.js — and you never have to think about SDK versions again. The loader resolves and injects the latest published core bundle at runtime, so an integrated app stays up to date with zero effort: no version pinning, no ?v= cache-buster to bump.

<script
  async
  src="https://js-sdk.zerogpu.ai/dist/loader.js"
  edgeOperatorKey="your-edge-operator-key"
  enableConsoleLogs="true"
></script>

The SDK auto-initializes when edgeOperatorKey is present (the loader forwards every attribute to the core bundle).

For manual initialization, embed the loader without keys and call ZeroGpuSdk.initZeroGpuSdk(...). The loader installs a small queueing stub, so calls made before the core bundle finishes loading are replayed automatically:

<script async src="https://js-sdk.zerogpu.ai/dist/loader.js"></script>
<script>
  ZeroGpuSdk.initZeroGpuSdk({
    edgeOperatorKey: 'your-edge-operator-key'
  });
</script>

How it works: loader.js and manifest.json are served fresh (short TTL + stale-while-revalidate); the manifest points at an immutable, content-hashed core bundle (dist/v/zerogpu-browser-sdk.<hash>.umd.js) cached for a year. A new release simply repoints the manifest at a new hash — and rollback is the same operation in reverse. If the manifest is ever unreachable, the loader falls back to the stable dist/zerogpu-browser-sdk.umd.js bundle.

Loading the core bundle directly (dist/zerogpu-browser-sdk.umd.js) still works but pins the app to whatever build is live at load time — prefer the loader so updates are automatic.

Release channels: js-sdk.zerogpu.ai serves tagged releases only — the production deploy is gated on a v* git tag (release tags may carry a prerelease suffix, e.g. v2.1.8-alpha), so an auto-updating embed can never receive an untagged branch build. Development builds live on the separate dev-js-sdk.zerogpu.ai / staging-js-sdk.zerogpu.ai domains (deployed from the dev/main branches) — point a test page at those to try unreleased builds.

Configuration Options

InitOptions

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | appUserId | string | undefined | Optional user identifier (e.g. Telegram ID) for telemetry. | | edgeOperatorKey | string | undefined | Operator key forwarded to /register as x-edge-operator-key. The orchestrator resolves the project from this key. | | overrides | Partial<SdkConfig> | {} | Deep merge overrides for internal config. | | customParams | { cust_param1?, cust_param2?, cust_param3? } | undefined | Operator macros attached to every request this device serves. See Custom macros. |

Off-main-thread inference (overrides.inference)

Model download, ONNX session creation and every inference run in a dedicated Worker the SDK spawns itself, so the host page's main thread never blocks (session creation alone froze it for 1–2 s per model before). The Worker is created from source bundled into the SDK — nothing extra to host — and the device protocol, outputs and the IndexedDB model cache are unchanged.

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | inference.worker | boolean | true | false forces the historical main-thread mode (e.g. an environment known to lack Workers). | | inference.workerUrl | string | undefined | Same-origin URL of dist/zerogpu-worker.js for pages whose Content-Security-Policy forbids blob: workers. |

When a Worker cannot be created or fails to boot, the SDK falls back to the main thread for the rest of the session and reports it once as a guardrail.pressure_warning event with code inference_worker_unavailable.

await initZeroGpuSdk({
  edgeOperatorKey: 'your-edge-operator-key',
  overrides: { inference: { worker: false } } // main-thread mode
});

Custom macros (cust_param1..3)

Three opaque slots for your own reporting dimensions — placement, cohort, campaign, app surface. ZeroGPU stores and counts them against every request your devices serve, never interprets them, and reports them back only to you (never to the API customer whose request the device served).

await initZeroGpuSdk({
  edgeOperatorKey: 'your-edge-operator-key',
  customParams: { cust_param1: 'placement_home', cust_param2: 'cohort_b' }
});

// Later — replaces the whole map; omitted slots become unset, {} clears all.
setCustomParams({ cust_param1: 'placement_settings' });

Script tag: data-cust-param1, data-cust-param2, data-cust-param3 (the loader forwards them). ZeroGpuSdk.setCustomParams(...) is queued like initZeroGpuSdk if called before the core bundle loads. Works the same inside Telegram Mini Apps.

  • Values only. The slot name is the key, so send the value itself (cust_param1: '1231231313'), never a nested parameter (cust_param1: 'user-id=1231231313'). Letters, digits, ., _ and - only; anything else is dropped with an always-on warning.
  • Strings, numbers and booleans are accepted (numbers/booleans become strings); other keys and types are dropped with a console warning (with enableConsoleLogs). Control characters are stripped, values are trimmed, and anything over 128 characters is truncated rather than rejected.
  • No personal data. Email-shaped values are dropped with an always-on warning. Values cannot be deleted individually once recorded.
  • setCustomParams applies from the next request served; no re-registration.

SdkConfig Overrides

You can override any part of the configuration. Common overrides:

  • orchestrator.baseUrl: URL of the ZeroGPU orchestration API.
  • slm.modelRepoId: Hugging Face repo id used by Transformers.js (default: Xenova/t5-small).
  • slm.modelUrl: Base URL that hosts the model assets (e.g., your CDN).
  • slm.sampleSummaryText: Text used for the on-device self-test before registration.
  • telemetry.locationData: If true, SDK attempts to gather GPS coordinates (triggers permission prompt).
  • telemetry.enableConsoleLogs: Force console logging on/off (default false). Logs are redacted by construction: message types, request/model/device ids, counts, byte sizes, durations and error codes only — never task text, model output, message frames or session credentials.
  • telemetry.cameraData: Deprecated and ignored. The camera-capture path was removed from the SDK entirely (ZGA-538); no camera code exists in the shipped bundle. The flag remains in the type only so existing integrations keep compiling.

Data collected at registration

The SDK collects coarse device-capability data and sends it to the ZeroGPU registry on POST /register so the orchestrator can decide which model (if any) fits this device: platform, user agent, language, timezone, CPU core count, approximate memory, screen size, battery level, connection type, page URL/referrer, and — only with the locationData opt-in — GPS coordinates.

WebGL renderer fingerprint

The SDK reads the WebGL renderer string (WEBGL_debug_renderer_info → UNMASKED_RENDERER_WEBGL, e.g. "Apple GPU" or "Adreno 660") and sends it in the register payload twice, as gpuRenderer and as webglFingerprint:

  • What it is: the GPU/driver identification string the browser exposes via WebGL. No canvas is rendered or hashed; the two fields currently carry the same raw string.
  • What it is used for: as a hardware-capability signal for model assignment (which model fits this GPU class), and as a device-identity anchor — a stability signal that helps the registry recognize a device across sessions alongside the stored deviceId (a random UUID persisted in browser storage).
  • What it is not: it is not used for cross-site tracking or advertising profiles, and it identifies a hardware class rather than a person — many devices share the same renderer string. Replacing this signal with per-device keypairs is planned (see the confidentiality roadmap); until then this documentation is the honest statement of what is collected.

Local Testing

Dashboard + Demo (Vite)

The Vite app under sdk/dashboard-app serves both:

  • / — ZeroGPU Edge SDK Demo
  • /dashboard — ZeroGPU Fleet dashboard (analytics)

It also proxies API calls so the browser avoids CORS:

  • /api/* -> API_UPSTREAM (default http://localhost:4000)
  • /analytics/* -> ANALYTICS_UPSTREAM (default http://localhost:5000)
cd sdk
npm run dashboard:dev

Build/preview:

cd sdk
npm run dashboard:build
npm run dashboard:preview

Env config:

  • Copy sdk/dashboard-app/.env.example to sdk/dashboard-app/.env.local and edit values.
  • By default it uses /api + /analytics so Vite can proxy and avoid browser CORS.
  • The demo page (/) can also read optional defaults from VITE_ZGPU_SDK_KEY and VITE_ZGPU_PROJECT_ID (recommended via .env.local, not committed).

Testing against a non-production orchestrator

Each deployment bakes in its own orchestrator at build time — develop, staging, or production (https://devices.zerogpu.ai) — via the ZGPU_ORCHESTRATOR_BASE_URL build env var set by the GitHub deploy workflows. For internal testing against a develop or local orchestration API, override orchestrator.baseUrl directly:

import { initZeroGpuSdk } from '@zerogpu/browser-extension-sdk';

await initZeroGpuSdk({
  edgeOperatorKey: 'your-edge-operator-key',
  overrides: {
    orchestrator: {
      // e.g. https://dev.devices.zerogpu.ai or http://localhost:6000
      baseUrl: 'http://localhost:6000'
    },
    telemetry: {
      enableConsoleLogs: true // Enable detailed logging
    }
  }
});

SDK Demo Page

Use the built-in demo page served by Vite at http://localhost:8000/ (it loads the SDK from /dist/zerogpu-browser-sdk.esm.js).

Self-Hosting the Model

If you want to serve the SLM artifacts from your own CDN (e.g., Cloudflare R2), download the Hugging Face assets and preserve the folder structure:

t5-small/
├── config.json
├── generation_config.json
├── tokenizer.json
├── tokenizer_config.json
├── special_tokens_map.json
├── spiece.model
└── onnx/
    ├── encoder_model_quantized.onnx
    └── decoder_model_merged_quantized.onnx

Download commands

mkdir -p t5-small/onnx
cd t5-small

BASE_META="https://huggingface.co/Xenova/t5-small/resolve/main"
BASE_ONNX="https://huggingface.co/Xenova/t5-small/resolve/main/onnx"

curl -L -o config.json                "$BASE_META/config.json"
curl -L -o generation_config.json     "$BASE_META/generation_config.json"
curl -L -o tokenizer.json             "$BASE_META/tokenizer.json"
curl -L -o tokenizer_config.json      "$BASE_META/tokenizer_config.json"
curl -L -o special_tokens_map.json    "$BASE_META/special_tokens_map.json"
curl -L -o spiece.model               "$BASE_META/spiece.model"
curl -L -o onnx/encoder_model_quantized.onnx        "$BASE_ONNX/encoder_model_quantized.onnx"
curl -L -o onnx/decoder_model_merged_quantized.onnx "$BASE_ONNX/decoder_model_merged_quantized.onnx"

Upload the t5-small/ directory to your CDN unchanged and ensure responses include permissive CORS headers (Access-Control-Allow-Origin: *). Then override the SDK config:

await initZeroGpuSdk({
  edgeOperatorKey: 'your-edge-operator-key',
  overrides: {
    slm: {
      modelUrl: 'https://cdn.example.com/models/t5-small'
    }
  }
});

slm.modelRepoId remains Xenova/t5-small so Transformers.js can reference the original repo, while the SDK rewrites every network request to your CDN.

Flow

  1. initZeroGpuSdk resolves configuration (env defaults + overrides).
  2. Device fingerprint + metadata are collected.
  3. Required SLM artifacts are downloaded to IndexedDB and loaded into Transformers.js. Timing metrics are recorded.
  4. The SDK calls the orchestrator /register endpoint with device + model metadata.
  5. The orchestrator responds with a wsUrl. The SDK opens a WebSocket, sends a hello, and listens for summary_request messages.
  6. Each summary_request executes against the on-device SLM (single flight enforced) and responds with summary_response containing the summarized text and rich metadata (timings, device info, model info).
  7. If the WebSocket closes or errors, the SDK marks the state as error. Reloading the host app re-initializes the SDK.