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

@rdf-label-cache/client

v0.1.1

Published

A thin, zero-dependency, isomorphic client for the RDF Label Cache - prefers the browser HTTP cache, parallel by default.

Readme

@rdf-label-cache/client

A really thin (one file, zero dependencies), isomorphic client for the RDF Label Cache. It is the canonical example of how to consume the service well — it encodes, in code, the guidance from consuming.md and FAQ.md:

  • Parallel by default, bounded to ~100 in flight — the per-connection H2/H3 stream limit. Independent, edge-cached GETs multiplexed over one warm connection.
  • Prefers the browser cache. It never busts it (no cache: "no-store"), so a returning view is served from the browser's own HTTP cache at 0 bytes on the wire. In the browser it adds only an in-flight de-dupe; outside the browser (Node/Workers/Deno — no shared HTTP cache) it keeps a small memo LRU.
  • Client-side language fallback. There is no server-side fallback; a ?lang= miss is corrected with a cheap, separately-cached second call.
  • Warms the connection with preconnect() (browsers).

Install

pnpm add @rdf-label-cache/client

Use

import { createLabelClient } from "@rdf-label-cache/client";

const labels = createLabelClient({
  base: "https://label-cache-orders.<subdomain>.workers.dev",
});

// Browser: warm the TLS/QUIC handshake as the page loads.
labels.preconnect();

// One label (untagged). Applies predicate order + language fallback.
await labels.resolve("https://schema.org/name");            // → "name"

// A specific language, falling back to the untagged label on a miss.
await labels.resolve("https://schema.org/name", { lang: "en" });

// Many at once — deduped, parallel, bounded. This is the hot path.
await labels.resolveMany([
  "https://schema.org/Person",
  "https://schema.org/jobTitle",
  "http://www.w3.org/2004/02/skos/core#Concept",
]);
// → { "https://schema.org/Person": "Person", … }

Need the raw JSON-LD instead of a single string? Use document(iri, lang?) / documentMany(iris, lang?) and pick with the exported pickLabel.

Getting real RDF out (still zero-dep)

The raw response is JSON-LD — as delivered it is only valid JSON; it becomes valid RDF once interpreted against the context (so prefLabel → skos:prefLabel, the "en" key → a language tag). You don't need a JSON-LD processor for that: the service's context is a trivial subset (prefix maps + @container: @language), so toQuads expands faithfully, driven by the service's own fetched context — correct even for self-hosters with custom predicates.

// Zero-dep: plain RDF/JS-shaped { subject, predicate, object, graph } objects.
const triples = await labels.toQuads(await labels.document("http://…/Concept", "en"));

// Already using n3? Hand it the DataFactory to get n3's native quads, straight
// into a Store — no jsonld dependency, no reinvention:
import { DataFactory, Store } from "n3";
const store = new Store();
store.addQuads(await labels.toQuads(doc, { factory: DataFactory }));

@none expands to an xsd:string literal, a real tag to an rdf:langString. toQuadsMany(docs, opts?) concatenates across documents.

Prefer a full JSON-LD processor?

This library intentionally does not depend on jsonld or n3 — most label cache consumers already have them, and dependency injection beats a bundled (or even optional) dependency. Two supported routes:

  1. toQuads({ factory }) as above — enough for this service's data, zero-dep.
  2. Bring your own parser for full JSON-LD 1.1 / streaming. Feed the raw response to jsonld-streaming-parser (the n3 companion) or jsonld, with the context served from memory via getContext() (it's versioned and immutable — cache it once, per consuming.md §3), so no per-document context round trip.

API

| Member | Purpose | |---|---| | createLabelClient(opts) / new LabelClient(opts) | Construct once, reuse — keeps the connection warm and caches live. | | .resolve(iri, { lang?, fallback? }) | IRI → label string (or null). | | .resolveMany(iris, opts?) | IRIs → { [iri]: label \| null }, concurrent & deduped. | | .document(iri, lang?) / .documentMany(iris, lang?) | Raw JSON-LD (or null on a miss). | | .toQuads(doc, { factory? }) / .toQuadsMany(docs, …) | Expand JSON-LD → RDF triples (zero-dep, or your RDF/JS DataFactory). | | .getContext() | The versioned, immutable context document (cached) — for a BYO JSON-LD parser's documentLoader. | | .url(iri, lang?) | The request URL for a pair (for <link rel=preload>, debugging). | | .preconnect() | Browser: preconnect to the origin. No-op elsewhere. | | pickLabel(doc, order?, lang?) / pickFromMap(map, lang) | Pure pickers, usable without a client. | | lruStore(max?) | The default memo store; pass your own via cache. |

Options

createLabelClient({
  base,                 // required: your deployed Worker origin
  order,                // preference by term ALIAS (doc keys, not IRIs); default ["prefLabel","label","title","name"]
  concurrency,          // max in-flight; default 100
  cache,                // "auto" (default) | true | false | your own LabelStore
  fetch,                // injectable fetch; default globalThis.fetch
});

cache: "auto" turns the memo LRU off in browsers (the HTTP cache already does this job and a hand-rolled map mostly duplicates it) and on everywhere else (server callers have no shared HTTP cache). Only successful documents are memoized — a miss is never cached, so a label seeded shortly after a 404 shows up on the next call.

order is matched against the term aliases in the response (the object's keys, e.g. prefLabel), not IRIs. The default matches the aliases this service's context emits. Because a term keeps its alias even if a deployment maps it to a different IRI, remapping (say name → foaf:name) needs no change; only a context that renames the aliases does — then pass your own order.

Why so thin?

Because the service is designed so the client can be thin: the edge cache, HPACK/QPACK header compression, and HTTP/3 stream multiplexing do the heavy lifting. The client's whole job is to fire requests in parallel, get out of the cache's way, and pick a label. See the FAQ for why "one request per label" is the right shape.