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

@azrtydxb/novamem

v1.1.3

Published

TypeScript client for the novamem memory service

Readme

@azrtydxb/novamem

TypeScript client for novamem, a tiered memory service with hybrid search, per-user isolation, and project (sub-brain) scoping.

npm install @azrtydxb/novamem

Quickstart

import { NovamemClient } from "@azrtydxb/novamem";

const memory = new NovamemClient({
  baseUrl: "http://localhost:7778",
  token: process.env.NOVAMEM_TOKEN, // user bearer `nm_…`
});

await memory.remember({ content: "User prefers dark roast" });
const hits = await memory.search({ query: "coffee preference", k: 5 });

A nm_… bearer carries every right the owning user has — the user's whole memory plus every project they're a member of. Mint one from the dashboard's API Tokens page.

Project-scoped operations

Each entry can belong to a project (sub-brain). Pass project (id or human name) to scope:

await memory.remember({ content: "phoenix sprint plan", project: "Phoenix" });
await memory.search({ query: "sprint", project: "Phoenix" });

When the user has an active project set (setActiveProject), memory_* calls without an explicit project arg default to it: search/recent/neighbors union user-global with the active project; remember/forget/update target the active project directly.

Memory.update — rewriting facts

When a fact changes (user moved cities, decision reversed, …) update the existing entry instead of forget+remember; preserves the entry's id, hit count, and graph edges.

const oldId = "01KQ…";
await memory.updateMemory(oldId, {
  content: "User profile: Pascal Watteel lives in Singapore.",
  confidence: 1.0,
});

API surface

Memory data plane

| Method | Description | |---|---| | search(req) | Hybrid keyword + vector + graph search | | remember(req) | Store a new entry; subject to the worthiness gate (pass force: true to bypass) | | updateMemory(id, req) | Rewrite an entry in place; preserves id + hits + edges | | recent(opts) | Newest entries by namespace | | today(opts) | Last-24h entries (sugar over recent) | | neighbors(opts) | Graph-neighbour traversal from a seed id | | forget(id, opts?) | Hard delete | | stats() | Per-namespace counts | | health() | Public liveness probe — returns { ok } only. Per-dependency status lives behind the admin-gated /v1/admin/health/deep route, which the client does not expose | | decay(opts?) | Run the warm→cold demotion pass on demand |

Projects

| Method | Description | |---|---| | listProjects() | Projects the user is a member of | | createProject({name}) | Caller becomes owner; id is server-assigned (ULID) | | deleteProject(id) | Owner-only; purges all project data | | listProjectMembers(id) | Members of a project | | addProjectMember(id, {username, role?}) | Owner-only; username must be the invitee's exact email address (the server resolves via findUserByExactEmail) | | removeProjectMember(id, userId) | Owner removes anyone; non-owner self-leave only | | removeProjectMemberByUsername(id, username) | Convenience — resolves the username via members listing |

Active project

| Method | Description | |---|---| | getActiveProject() | Current pointer or { active: null } | | setActiveProject(project) | Set active project (id or name); membership-checked | | clearActiveProject() | Drop the pointer |

Tokens

| Method | Description | |---|---| | mintToken({label?}) | Plaintext shown once | | listTokens() | sha256 hashes + metadata | | revokeMyToken(tokenHash) | Hard-delete a bearer by sha256 hash (DELETE /v1/me/tokens/:hash) |

Dashboard auth (browser-style flow)

For non-browser callers that prefer a username + password flow over minting a nm_… bearer, the client also exposes login({ email, password }) / logout() / me() — these talk to Better Auth's /api/auth/* and store the resulting session bearer on the client. Most non-browser callers should use a nm_… token directly instead.

Notes

  • The client uses native fetch (Node ≥ 20 or any modern browser).
  • setToken(t) lets you swap the bearer in place (e.g. after a token rotation).
  • Pass fetch in the constructor for testing or to use a different fetch impl.
  • Errors throw with Error("novamem <status>: <body>") — handle as you would any fetch error.

See the main repo for the full API + dashboard documentation.