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

@arraypress/jsonld

v1.4.0

Published

JSON-LD structured data builders for SEO — Product, Article, BlogPosting, NewsArticle, Person, Organization, WebSite, WebPage, ProfilePage, Breadcrumb, FAQ, HowTo, Event, JobPosting, LocalBusiness, SoftwareApplication, Course, Recipe, VideoObject, ImageOb

Readme

@arraypress/jsonld

JSON-LD structured data builders for SEO — the markup that turns a plain blue link into a rich result with stars, prices, opening hours or a carousel. Content, commerce, local business, property, music and careers. Zero dependencies.

Installation

npm install @arraypress/jsonld

Usage

import { product, breadcrumb, faq } from '@arraypress/jsonld';

const ld = product({ name: 'Widget', url: 'https://example.com/widget', price: 9.99, currency: 'usd' });

API

All functions return a plain object with @context: "https://schema.org".

Commerceproduct(options) (offers, ratings, reviews, custom properties), offer(options), review(options), aggregateRating(options)

Contentarticle(options), blogPosting(options), newsArticle(options), recipe(options), videoObject(options), imageObject(options)

Entitiesperson(options), organization(options)

Site structurewebSite(options) (with search action), webPage(options), profilePage(options), breadcrumb(items), faq(items), howTo(options), collectionPage(options)

Local / business / careers / learningevent(options), localBusiness(options), jobPosting(options), softwareApplication(options), course(options), service(options)

DirectoriesitemList(options)

Foodmenu(options), menuSection(options), menuItem(options)

PropertyrealEstateListing(options), accommodation(options)

MusicmusicGroup(options), musicAlbum(options), musicRecording(options)

Directory sites

One localBusiness() serves every vertical: pass type to narrow it to any Schema.org LocalBusiness subtype. Google treats the subtype as a LocalBusiness for rich results and uses it to understand the vertical, so a narrower type is always better than the bare default.

localBusiness({
  type: 'Dentist',                    // or Restaurant, AutoRepair, HairSalon, MusicVenue…
  name: 'Bristol Smile Clinic',
  address: { streetAddress: '12 Park St', addressLocality: 'Bristol', postalCode: 'BS1 5JA' },
  phone: '+44 117 000 0000',
  openingHours: [
    { days: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], opens: '09:00', closes: '17:30' },
    { days: 'Sat', opens: '09:00', closes: '13:00' },
    { days: 'Sun', closed: true },
  ],
});

Day names accept 'Mon', 'monday' or 'Monday'. A day marked closed is emitted as 00:0000:00, which is Google's convention — leaving a day out says "unknown", which is a different claim.

The type option is a checked union covering the whole tree — automotive, medical, food, health and beauty, trades, professional, entertainment, sport, lodging and retail. See LocalBusinessType in the type definitions. organization(), event() and accommodation() take the same treatment via OrganizationType, EventType and AccommodationType.

Listing pages

itemList() is what makes "Dentists in Bristol" eligible for a carousel rather than a single link. It composes with the other builders — pass whole nodes in and the nesting is handled:

itemList({
  name: 'Dentists in Bristol',
  url: 'https://example.com/bristol/dentists',
  items: practices.map((p) => localBusiness({ type: 'Dentist', ...p })),
  startPosition: 41,      // page 3 of an archive — don't restart at 1
  totalItems: 220,
});

Every builder accepts an extra field (merged last) for any Schema.org property it doesn't model — declare the common 90%, bolt on the long tail. extra can also override @type for a subtype no union covers yet. See src/index.d.ts for full option details.

Using it with @arraypress/seo

The builders return plain objects; seo serialises them into the page. Nothing here knows about seo, so the same objects work in a Worker returning JSON-LD from an API.

---
import { SEO } from '@arraypress/seo-astro';
import { organization, breadcrumb } from '@arraypress/jsonld';

const ld = [
  organization({ name: 'Acme', url: Astro.site.href }),
  breadcrumb([{ name: 'Home', item: '/' }, { name: 'Dentists' }]),
];
---
<SEO title="Dentists in Bristol" jsonLd={ld} />

Validation

npm test runs the behavioural suite; npm run validate type-checks a sample of every builder's output against schema-dts — the TypeScript types generated from the Schema.org vocabulary itself — so an invalid property fails the build rather than shipping. That check has already caught real bugs: it rejected an address on RealEstateListing, which descends from WebPage and has no such property (it belongs on the nested Accommodation).

Bear in mind Google's requirements are stricter than Schema.org's. Schema.org marks nearly everything optional; Google silently drops a rich result when a required property is missing. Validating the shape is necessary but not sufficient — check new types against the Rich Results Test too.

License

MIT