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

@music-vine/setlist

v0.1.0

Published

Uppbeat's catalogue queries: one layer on top of Typesense, shared by every app that lists assets

Readme

@music-vine/setlist

Uppbeat's catalogue queries. One layer on top of Typesense, so every app that lists assets gets the same assets in the same order as uppbeat.io.

npm install @music-vine/setlist

It ships ES modules for a bundler (Vite, Next.js, webpack) and runs in the browser or on a server.

Setup

import { createSetlist } from '@music-vine/setlist';

export const setlist = createSetlist({
  nodes: [{ host: 'xxx.a1.typesense.net', port: 443, protocol: 'https' }],
  apiKey: searchOnlyKey,
  onError: (error, { operation, ...extra }) => report(error, operation, extra),
});
  • The key must be search-only. In a browser app it is public.
  • The package never reads environment variables. Pass hosts and the key in.
  • onError is called when a query fails and the caller gets an empty result instead. Queries that have no sensible empty result throw.

Pages

const { hits, found } = await setlist.getAssetsForPage({
  type: 'sfx',
  slug: '/sfx/category/whoosh',
});

type is music, sfx, motion-graphics, luts or stock-video. slug is the page's full path on the site.

| Option | Default | Meaning | | --- | --- | --- | | isSubscribed | false | Rank and tier results as a subscriber sees them. | | intersperse | true | Mix free and premium results. Only applies to non-subscribers on the default sort. | | sort | relevancy | Or latest, undiscovered. | | page, perPage | 1, per type | Pagination. | | filterBy, q | none | Extra Typesense filter and search text. |

It returns hits in the order the page shows them, found, and results (the raw result sets, [premium, free] when interspersed).

Music category pages need pageFilter. Their rule is compiled by the API (GET /api/v1/track-tags/page/{slug}, field filter), not stored in Typesense, so the caller passes it and the call throws without it. Music collection pages and every other asset type resolve from slug alone.

await setlist.getAssetsForPage({
  type: 'music',
  slug: '/music/category/jazz',
  pageFilter: page.filter,
});

A slug with no category throws rather than returning an empty list.

Search and similar assets

await setlist.searchAssets({ type: 'luts', q: 'moody' });
await setlist.getSimilarAssets({
  type: 'music',
  reference: trackDocument,
  excludeId: trackDocument.track_id,
});

getSimilarAssets takes the reference document rather than an id, so an asset can be checked before it is indexed. It covers music and SFX. Pass excludeId to leave the reference itself out of the results.

Carousels

A page's carousels are two searches, one for the carousels curated for the page and one for those matched from its search term:

import { getPageCarouselSearchParameters } from '@music-vine/setlist';

const { pageSearchParameters, autoSearchParameters } =
  getPageCarouselSearchParameters({
    library: 'music',
    name: 'Jazz',
    url: '/music/category/jazz',
    searchTerm: 'jazz',
  });

await setlist.getCarouselsMulti(pageSearchParameters, autoSearchParameters);

Errors

Two behaviours, depending on the query:

  • Listings throw. getAssetsForPage, searchAssets, getSimilarAssets and getCarouselsMulti reject when Typesense fails or times out, when a slug has no category, and when a music category page has no pageFilter. Catch them where you render.
  • Lookups report and return empty. getTrack, getSfx, getSfxVariants and the contributor queries resolve to null, [] or {} on failure and call onError(error, { operation, ...details }). Without an onError the failure is silent, so pass one.

The client retries across the nodes you give it before a query fails.

Reference

Every query is a method on the instance. Arguments and results are typed, so an editor shows the exact shape.

| To show | Call | | --- | --- | | What a page lists | getAssetsForPage | | Search results for one asset type | searchAssets | | Search results as the site's search page builds them | fetchSearchResults | | Assets similar to a music or SFX document | getSimilarAssets | | Similar motion graphics or LUTs, similar stock videos | fetchSimilarMotionGraphics, fetchSimilarStockVideos | | A page's carousels | getCarouselsMulti (see above), getCarousels | | One track, one SFX, an SFX's other variants | getTrack, getSfx, getSfxVariants | | A motion graphics or LUT category, and the filters it preselects | getMotionGraphicsCategory, getCategoryPreselectedFilters, getLutCategoryPreselectedFilters | | The LUT categories an asset appears in | fetchLutCategoriesForAsset | | A stock video category, its groups, related categories | getVideoCategory, getVideoCategoryGroups, getVideoCategoriesByGroup, getSimilarCategories | | Stock video listings | getStockFootage, getStockFootageByCategoryEmbedding, getStockFootageZoneSampled, fetchBatchStockVideos | | A contributor's profile, slug or asset count | getContributor, getContributorSlugByName, getContributorSlugsByNames, getContributorAssetCount | | Where an old URL redirects | getPageRedirect |

The package also exports the request builders, collection names and document types behind these.

setlist.multiSearch and setlist.searchCollection send a request as-is. They exist for queries with no named function yet; prefer a named one, and add one here when several callers need the same request.

Changing a query

The requests are pinned by src/golden-requests.test.ts. A snapshot diff there means the site and every other consumer will show different results, so update it only when that is the intent.