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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@24hr/content-next

v3.0.16

Published

[![pipeline status](https://gitlab.24hr.se/rawb/services/content-next/badges/master/pipeline.svg)](https://gitlab.24hr.se/rawb/services/content-next/commits/master) [![coverage report](https://gitlab.24hr.se/rawb/services/content-next/badges/master/covera

Readme

Content Service 2.0

pipeline status coverage report

What is it?

The Content Service is layer between a source of data, such as a CMS, and where the data will be consumed. It both adds functionality to a CMS, such as WP, and drastically increases the performance. It is designed to be CMS agnostic .

Why?

Most of the CMSes out there, both headless or conventional, need to accommodate lots of features. However these features are solved, the end solution is always a compromise. In some cases a CMS might be super fast but less flexible, or very modular and developer friendly but at the cost of a good editor experience.

The Content Service was originally created to add functionality to Wordpress, such as a draft and a live version without the need of double installations. It also serves all content from memory, making it much, much faster than traditional CMSs.

Versions

  • 2024-12-18: 3.0.0 Added meta column.
  • 2024-10-09: 2.2.10 Added a new query where you can do a shallow check if certain keys/permalinks exists without returning the whole resource
  • 2023-05-16: 2.1.0 Reworked cache to use redis instead of in memory. To run the tests, a local redis server is reuqired for now
  • 2023-05-16: 2.0.18 Added option to disable useSaveTree as a boolean so we can deactivate the whole hierarchy.

How it works

Mechanics

The Content Service normally two consumers:

  1. A source that pushes data into it, such as a CMS
  2. One or more consumers of the data

Source

The source need to be configurable somehow to push data to the Content Service. In the case of Wordpress, we use hooks to push data every time a post, page, or anything else has been saved in Wordpress. We push the data from the source to a target in the Content Service. A normal setup has a draft and a live target. draft is always (or should be) in sync with the source and live is only in sync with draft when someone wants to publish something the public site.

Consumers

A consumer is typically an API or a web site. It fetches the data from the Content Service and renders it as it needs. A consumer will normally never access the data directly form the source. It will always get the data from the Content Service.

Concepts

The Content Service follows these ideas:

  • It's NOT developed for a single specific project. On the contrary, it can be used by many different projects.
  • It's NOT aware of what data it holds. This means that no feature can be written specifically for some content (for example, nothing should exists that asumes the data in a resource contant vc_content or a property called blocks).
  • Everything is loaded in memory and kept there. If something changes, the cache will adapt (currently we have one place where we read from the DB, but that will be removed soon).
  • It is quite stupid. It saves each resource as one row in the DB, and fetches that resource based on its key or externalId. It has a couple of helper functions, but not much.

Ways of using it

THIS IS NOT TRUE YET: In its current state, the Content Service can be only be used as a NPM module. No docker image exists.

Docker (NOT YET)

Get it from docker hub at:

24hrservice/rawb-content-service-next:latest

NPM

npm install @24hr/rawb-content-service —save

Changes from version 1.0

  • It only uses graphql.
  • It doesn't need two instances, one for draft and one for live.
  • It's an NPM module.
  • You can have as many targets as needed (in 1.0 there was no concept of "targets". We had draft and live as hardcoded targets).
  • The code is cleaner. Many old things have been removed such as a fallback language, huge files and dependencies to things that should be something else.
  • No direct connection with an elastic search service.
  • No filters that are aware of the data each resource holds.

Concepts

Every entry that is pushed to the Content Service is called a resource. It consist of the following parameters:

  • a key (required), mostly used for the slug, so that a site quickly can fetch the data for a page.
  • an externalId (required), referencing to the id of the resource, so that a change in the key can be done to a resource.
  • a parentId (optional), reference to an externalId so we can create hierarchy.
  • a type (required) used to categorize content
  • a date (optional) used to sort by date. Its value is dictated by whatever the source sees as the correct date to be used.
  • a host (optional) to save where the data comes from (used in rare cases to access the data from the source)
  • userInfo (required), to audit logs
  • content (required) then content itself, the main body. This is the content of the page, everything else is meta-data.

Development

To begin development, do the following:

cd ./dev
docker-compose up

This will start a database (mariadb), a redis instance (for event emitting) and a nodejs project that runs them NPM module.

Current state

Features

Needs to be done as soon as possible

  • Create a new or an updated Wordpress plugin to interact with the Content Service. The current WP Plugin is NOT compatible with this.

Future plans

These are some of the features we plan to do:

  • Feature flags - A list of flags with options that can be used to filter out objects in the content of a resource.
  • Protected Resources - A way of making a resource not deletable.

Compatibility with previous version

Other parts

WP Plugin

Feature Flags React module

Enable db auto-sync (from 2.1.20)

Content service will no longer auto-create database tables. This is to prevent malicious requests from creating tables in the database. To enable it again in local development, add the following environment variable: ALLOW_CREATE=true DO NOT ENABLE THIS IN PRODUCTION!

Add meta column (from 3.0.0)

DO $$
DECLARE
    tbl_name text;
BEGIN
    FOR tbl_name IN
        SELECT table_name
        FROM information_schema.tables
        WHERE table_schema = 'public' -- Adjust schema if needed
          AND table_name != 'contexts' -- Exclude the "contexts" table
    LOOP
        EXECUTE format('ALTER TABLE %I ADD COLUMN IF NOT EXISTS meta jsonb;', tbl_name);
    END LOOP;
END $$;