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

@n1ru4l/in-memory-live-query-store

v0.11.0

Published

[![npm version](https://img.shields.io/npm/v/@n1ru4l/in-memory-live-query-store.svg)](https://www.npmjs.com/package/@n1ru4l/in-memory-live-query-store) [![npm downloads](https://img.shields.io/npm/dm/@n1ru4l/in-memory-live-query-store.svg)](https://www.np

Readme

@n1ru4l/in-memory-live-query-store

npm version npm downloads

A GraphQL live query store that tracks, invalidates and re-executes registered operations. Drop in replacement for graphql-js execute. Add live query capabilities to your existing GraphQL schema.

Check out the todo example server for a sample integration.

Install Instructions

yarn add -E @n1ru4l/in-memory-live-query-store

API

InMemoryLiveQueryStore

A InMemoryLiveQueryStore instance tracks, invalidates and re-executes registered live query operations.

The store will keep track of all root query field coordinates (e.g. Query.todos) and global resource identifiers (e.g. Todo:1). The store can than be notified to re-execute live query operations that select a given root query field or resource identifier by calling the invalidate method with the corresponding values.

A resource identifier is composed out of the typename and the actual resolved id value separated by a colon, but can be customized. For ensuring that the store keeps track of all your query resources you should always select the id field on your object types. The store will only keep track of fields with the name id and the type ID! (GraphQLNonNull(GraphQLID)).

import { InMemoryLiveQueryStore } from "@n1ru4l/in-memory-live-query-store";
import { parse, execute as executeImplementation } from "graphql";
import { schema } from "./schema";

const inMemoryLiveQueryStore = new InMemoryLiveQueryStore();

const rootValue = {
  todos: [
    {
      id: "1",
      content: "Foo",
      isComplete: false,
    },
  ],
};

const execute = inMemoryLiveQueryStore.makeExecute(executeImplementation);

execute({
  schema, // make sure your schema has the GraphQLLiveDirective from @n1ru4l/graphql-live-query
  operationDocument: parse(/* GraphQL */ `
    query todosQuery @live {
      todos {
        id
        content
        isComplete
      }
    }
  `),
  rootValue: rootValue,
  contextValue: {},
  variableValues: null,
  operationName: "todosQuery",
}).then(async (result) => {
  if (isAsyncIterable(result)) {
    for (const value of result) {
      console.log(value);
    }
  }
});

// Invalidate by resource identifier
rootValue.todos[0].isComplete = true;
inMemoryLiveQueryStore.invalidate(`Todo:1`);

// Invalidate by root query field coordinate
rootValue.todos.push({ id: "2", content: "Baz", isComplete: false });
inMemoryLiveQueryStore.invalidate(`Query.todos`);

The execute function returned from InMemoryLiveQueryStore.makeExecute is a drop-in replacement for the default execute function exported from graphql-js. You can provide your own execute function from any graphql-js version or other library.

Pass it to your favorite graphql transport that supports returning AsyncIterableIterator (or AsyncGenerator) from execute and thus delivering incremental query execution results.

List of known and tested compatible transports/servers:

| Package | Transport | Version | Downloads | | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | @n1ru4l/socket-io-graphql-server | WebSocket/HTTP Long Polling | npm version | npm downloads | | graphql-helix | HTTP/SSE | npm version | npm downloads | | graphql-ws | WebSocket | npm version | npm downloads |

Recipes

Using with Redis

You can use Redis to synchronize invalidations across multiple instances. A full runnable example can be found here.

import Redis from "ioredis";
import { InMemoryLiveQueryStore } from "@n1ru4l/in-memory-live-query-store";
import { execute as defaultExecute } from "graphql";

const inMemoryLiveQueryStore = new InMemoryLiveQueryStore();

const client = new Redis(redisUri);
const subClient = new Redis(redisUri);

class RedisLiveQueryStore {
  pub: Redis;
  sub: Redis;
  channel: string;
  liveQueryStore: InMemoryLiveQueryStore;

  constructor(
    pub: Redis,
    sub: Redis,
    channel: string,
    liveQueryStore: InMemoryLiveQueryStore
  ) {
    this.pub = pub;
    this.sub = sub;
    this.liveQueryStore = liveQueryStore;
    this.channel = channel;

    this.sub.subscribe(this.channel, (err) => {
      if (err) throw err;
    });

    this.sub.on("message", (channel, resourceIdentifier) => {
      if (channel === this.channel && resourceIdentifier)
        this.liveQueryStore.invalidate(resourceIdentifier);
    });
  }

  async invalidate(identifiers: Array<string> | string) {
    if (typeof identifiers === "string") {
      identifiers = [identifiers];
    }
    for (const identifier of identifiers) {
      this.pub.publish(this.channel, identifier);
    }
  }

  makeExecute(execute: typeof defaultExecute) {
    return this.liveQueryStore.makeExecute(execute);
  }
}

const liveQueryStore = new RedisLiveQueryStore(
  client,
  subClient,
  "live-query-invalidations",
  inMemoryLiveQueryStore
);