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

cos-resource-fetcher

v0.1.2

Published

Fetch resource blobs via Cross-Origin Storage (COS) with Cache API fallback. Defaults to Hugging Face SHA-256 resolution, but accepts any custom resolver.

Readme

cos-resource-fetcher

Fetches large resource blobs (model weights, Wasm files,…) using the Cross-Origin Storage (COS) API when available, with the Cache API as an automatic fallback.

Progressive enhancement — the library works without any configuration regardless of browser support. If COS is available it is used automatically; if not, the Cache API takes over transparently. No feature-detection or conditionals needed in your code.

Why COS? The Cache API stores a separate copy per origin. COS stores a single copy keyed by content hash that every origin on the device can reuse. This means a 2 GB model downloaded by one site is instantly available to any other site that asks for the same hash. See the COS explainer for the full proposal and the Chrome extension to enable it while the API is not yet shipped.

Installation

npm install cos-resource-fetcher

Usage

Default: Hugging Face URL

Pass a Hugging Face /resolve/ URL — the library resolves the required SHA-256 automatically via the Git LFS pointer endpoint.

import { fetchBlob } from 'cos-resource-fetcher';

const blob = await fetchBlob(
  'https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm/resolve/main/gemma-4-E2B-it-web.litertlm',
  {
    onProgress({ loaded, total }) {
      const percent = total
        ? ((loaded / total) * 100).toFixed(1) + '%'
        : `${loaded} bytes`;
      console.log(`Downloading… ${percent}`);
    },
  }
);

The fetchBlob() function returns a Blob. On first call it downloads the file and stores it in COS (or the Cache API). Subsequent calls from the same origin skip both the hash lookup and the download. Subsequent calls from a different origin still need one small network request to resolve the SHA-256 (the hash cache is per-origin), but the file itself is served from COS without re-downloading.

Custom SHA-256 resolver

If you already know the hash, pass it directly via sha256:

import { fetchBlob } from 'cos-resource-fetcher';

const blob = await fetchBlob(
  'https://example.com/models/gemma-4-E2B-it-web.litertlm',
  {
    sha256: 'abcdef0123456789…', // replace with the real hash
    onProgress({ loaded, total }) {
      const loadedGB = (loaded / 1e9).toFixed(2);
      if (total) {
        const percent = ((loaded / total) * 100).toFixed(1);
        console.log(
          `${percent}% — ${loadedGB} / ${(total / 1e9).toFixed(2)} GB`
        );
      }
    },
  }
);

If your URL is not on Hugging Face and you need to derive the hash at runtime, pass a getSHA256 function:

const blob = await fetchBlob(modelUrl, {
  getSHA256: async (url) => {
    const res = await fetch(
      '/api/resource-hash?url=' + encodeURIComponent(url)
    );
    const { sha256 } = await res.json();
    return sha256;
  },
});

Resources from npm

For any resource hosted on npm, SHA-256 hashes are available because npm packages are mirrored on jsDelivr, which exposes a per-file hash for every package version. The npm-sha256-hash-fetcher library wraps the jsDelivr API and converts the base64 hash it returns into hex:

import { fetchBlob } from 'cos-resource-fetcher';
import { NPMSHA256HashFetcher } from 'npm-sha256-hash-fetcher';

const fetcher = new NPMSHA256HashFetcher();

const blob = await fetchBlob(cdnUrl, {
  getSHA256: async () => {
    const [result] = await fetcher.getHexHashForResource(
      '[email protected]/path/to/resource.bin'
    );
    if (result.status !== 'fulfilled') throw result.reason;
    return result.value.hexHash;
  },
});

Options

| Option | Type | Default | Description | | ------------ | ----------------------------------------------------- | -------------------------------------- | --------------------------------------------------------------------------- | | sha256 | string | — | Lowercase hex SHA-256, if already known. Takes precedence over getSHA256. | | getSHA256 | (url: string) => Promise<string> | getHuggingFaceSHA256 | Derives the SHA-256 at runtime. Only called when sha256 is not provided. | | onProgress | ({ loaded: number, total: number \| null }) => void | — | Called with byte counts during a network download. | | cacheName | string | 'cos-resource-fetcher' | Cache API bucket used by the fallback path. |

Resolving a Hugging Face SHA-256 manually

The named export getHuggingFaceSHA256 is also available if you need the hash independently:

import { getHuggingFaceSHA256 } from 'cos-resource-fetcher';

const sha256 = await getHuggingFaceSHA256(
  'https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm/resolve/main/gemma-4-E2B-it-web.litertlm'
);
console.log(sha256); // e.g. "3f4a…"

Demo

demo/ contains a working chat UI powered by LiteRT-LM JS. It uses fetchBlob() to load the Gemma 4 E2B model weight and streams responses token-by-token.

cd demo
npm install
npm run dev

How the fallback works

navigator.crossOriginStorage available?
  ├─ yes → look up hash in COS
  │         ├─ found → return cached blob (zero download)
  │         └─ not found → download → write to COS → return blob
  └─ no  → look up URL in Cache API
            ├─ found → return cached response blob
            └─ not found → download → write to cache → return blob

License

Apache-2.0