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

@asterql/view-protocol

v0.3.0

Published

Registered AsterQL view ids, manifests, params URLs, and handlers.

Readme

@asterql/view-protocol

npm install @asterql/view-protocol

Registered view definitions, deterministic view ids, canonical params, and a small handler shape for AsterQL.

This package is the bridge between "run this query locally" and "ship a cacheable UI data endpoint." Production requests use manifest-backed ids, while local tools can opt into raw query evaluation explicitly.

import {
  createViewCacheHeaders,
  createManifest,
  createViewHandler,
  createViewUrl,
  defineView,
} from "@asterql/view-protocol";

const recentOrders = defineView({
  service: "dashboard",
  query: `*.orders[status == $status] | sort(-createdAt)[:10]{id, total}`,
});

const manifest = createManifest([recentOrders]);
const url = createViewUrl(recentOrders, { status: "paid" });
const cacheHeaders = createViewCacheHeaders(recentOrders, { status: "paid" });

const handle = createViewHandler({
  views: [recentOrders],
  async load({ params }) {
    return loadDashboardData(params);
  },
});

API

  • defineView(input): normalize a query and compute a deterministic view id.
  • getViewId(view): return the content hash id for a view.
  • createManifest(views): emit a stable manifest keyed by view id.
  • createViewETag(view, params?, options?): compute a weak ETag from the view id, canonical params hash, and optional service data version.
  • createViewCacheHeaders(view, params?, options?): create Cache-Control and ETag headers from the view cache policy.
  • encodeParams(params) / decodeParams(value): base64url canonical JSON.
  • createViewUrl(view, params?, options?): build /views/:viewId URLs.
  • createViewHandler(options): execute registered views against host data.
  • fetchView(view, params?, options?): tiny fetch helper for clients.

State sync primitives:

  • createEntityKey(kind, id) / parseEntityKey(key): stable normalized entity ids in kind:id form.
  • createScopeKey(kind, id) / parseScopeKey(scope): stable scope ids such as agent:agent_123.
  • hashRecordVersion(input) and hashServerEventId(input): deterministic record/event ids over canonical JSON.
  • ServerEvent, ServerEventEnvelope, EntityRecord, EntityPatch, and InvalidationClass: browser-safe wire and store contracts for normalized state sync.
  • invalidationIntersects(a, b): match entity, entity-kind, scope, service, and view invalidation classes.
  • parseEntityPath(path) / formatEntityPath(path): JSON Pointer helpers for patch paths.
  • getEntityPathValue, setEntityPathValue, unsetEntityPathValue, applyEntityPatch, and applyEntityPatches: immutable JSON patch helpers for set, unset, merge, appendText, keyed insert, and removeKey.
  • canonicalJsonBytes(value), sha256Base64Url(bytes), hashCanonicalJson(prefix, value), hashParams, hashSchema, and hashViewDefinition: canonical hashing helpers matching the package's existing view/schema/params ids.
  • createVersionedViewETag(input) / parseVersionedViewETag(etag): weak ETags that embed the view id, canonical params hash, auth-scope hash, body hash, and a sorted invalidation-class version map, so revalidation can answer "did any class this view depends on advance?" from the ETag alone.
  • formatInvalidationClass(class), classVersionFromDate(value), mergeClassVersions(...maps), advancedClassVersions(current, baseline, keys?), classVersionsFromETagPayload(payload), hashAuthScope(value), and ifNoneMatchIncludes(header, etag): the class-version vocabulary used by versioned ETags and invalidation-driven cache revalidation.

The handler only executes registered views by default. Registered view responses include explicit cache headers: views with a cache policy use that policy, and views without one are no-store. Raw dev _eval responses are always no-store and exist only when allowEval: true is passed.