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

@aminoxix/schemind

v0.5.6

Published

Language-agnostic API response shape intelligence — detects when your API's shape silently changes.

Downloads

244

Readme

schemind

your API's shape has a mind of its own. schemind watches it.

npm license node zero deps

Quickstart · How it works · Integrations · CI gate · Backend adapters


The problem

Your frontend calls /api/users/:id and trusts the shape of what comes back. Then, one day, a backend team renames author to authorInfo, or a field quietly becomes nullable — and nothing tells you until a user hits a blank screen in production.

No OpenAPI spec catches this if it's out of date. No TypeScript type catches this if the backend and frontend are different teams, different languages, or different repos entirely.

schemind watches the actual shape of your API responses at runtime and tells you the moment it changes — no spec to write, no types to maintain.


Quickstart

npm install @aminoxix/schemind
# or
pnpm add @aminoxix/schemind

Drop it into your existing fetch calls — no rewrite required:

import { createSchemindFetch } from "@aminoxix/schemind";

const fetch = createSchemindFetch({
  onObserve: ({ endpoint, report }) => {
    if (report?.severity === "breaking") {
      console.error("API drift detected!", endpoint, report);
    }
  },
});

// every call through this fetch is now observed automatically
const res = await fetch("/api/users/42");

Requires Node.js ≥ 18 · zero runtime dependencies · works in browser, edge, and Node.


How it works

schemind intercepts your API calls, extracts the structural shape of each JSON response (field names, types, nesting — never the actual values), and compares it to a stored baseline. When the shape drifts, you get a precise path and severity.

GET /api/users/:id  →  shape extracted  →  compared to baseline
                                                     │
                              field_removed     →  🔴 breaking
                              became_nullable   →  🟡 warn
                              field_added       →  🔵 info

The baseline is created automatically on first sight — subsequent calls diff against it. No schema to hand-write, ever.

| Change | Severity | |---|---| | field_removed | 🔴 breaking | | type_changed | 🔴 breaking | | array_item_changed | 🔴 breaking | | became_nullable | 🟡 warn | | became_required | 🟡 warn | | field_added | 🔵 info |


Integrations

schemind ships first-class adapters for whatever you're already using — pick one, no other code changes needed.

Fetch wrapper — the fastest way in

import { createSchemindFetch } from "@aminoxix/schemind";

export const fetch = createSchemindFetch({
  onObserve: ({ endpoint, report }) => {
    if (!report || report.changes.length === 0) return;
    console.warn(`[drift] ${endpoint}`, report);
  },
});

Express middleware

import { schemindExpress } from "@aminoxix/schemind/express";

app.use(express.json()); // must come first
app.use(schemindExpress({
  onObserve: (r) => r.report && console.log(r.report),
}));

Next.js route wrapper

import { withSchemind } from "@aminoxix/schemind/next";

export const GET = withSchemind(async (req) => {
  return Response.json(await getUsers());
});

Hono middleware

import { schemindHono } from "@aminoxix/schemind/hono";

app.use("*", schemindHono());

TanStack Query gets its own zero-touch integration — wrap your QueryClient once and every useQuery / useMutation in the app is observed automatically:

import { createSchemindQueryClient } from "@aminoxix/schemind/tanstack";

const queryClient = createSchemindQueryClient({
  onObserve: ({ endpoint, report }) => {
    if (report?.severity === "breaking") console.error("drift!", endpoint, report);
  },
});

Per-query hooks (useSchemindQuery, useSchemindMutation) and a low-level wrapQueryFn are also available for finer control — see the full docs.


CI gate — catch drift before it ships

The schm CLI probes your API, diffs shapes against a committed baseline, and fails the build on breaking drift. It's a contract test that needs no spec to maintain.

# scaffold config + routes file (run once)
npx schm init

# run the gate
npx schm ci --base-url https://staging.api.com --routes ./routes.json
[
  { "method": "GET",  "path": "/api/users" },
  { "method": "GET",  "path": "/api/users/:id", "params": { "id": "1" } },
  { "method": "POST", "path": "/api/auth/login", "body": { "email": "[email protected]", "password": "x" } }
]

GitHub Action

- uses: aminoxix/[email protected]
  with:
    base-url: https://staging.api.com
    routes: ./routes.json
    fail-on: breaking   # info | warn | breaking
    comment: true       # post/update a PR comment with the drift table

Persist baselines across runs

By default baselines live in memory and vanish on restart. Persist them so CI has something real to diff against:

import { createSchemind, SnapshotStore } from "@aminoxix/schemind";
import { LocalStorageDriver } from "@aminoxix/schemind/node";

const engine = createSchemind({
  store: new SnapshotStore(new LocalStorageDriver(".schemind/snapshots")),
});

Commit .schemind/snapshots/ to git so CI always has a baseline.

| Driver | Import | Use case | |---|---|---| | MemoryStorageDriver (default) | @aminoxix/schemind | tests, browser | | LocalStorageDriver | @aminoxix/schemind/node | local dev, CI with git-committed snapshots | | RedisStorageDriver | @aminoxix/schemind/node | shared baseline across instances | | S3StorageDriver | @aminoxix/schemind/node | durable shared baseline in CI |

Redis and S3 are bring-your-own-client — schemind stays dependency-free.


Reduce noise

Ignore volatile fields (updatedAt, requestId, etc.) that change on every request but aren't real drift:

export default defineConfig({
  ignoreFields: ["updatedAt", "createdAt", "requestId"],
  ignorePaths: ["**.timestamp", "data[].traceId"],
});

Notifications

Wire reporters straight into schemind.config.mjs — Slack, GitHub PR comments, generic webhooks (HMAC-signable), PagerDuty, and OpenTelemetry are all built in.

import { defineConfig, slackReporter, githubReporter } from "@aminoxix/schemind";

export default defineConfig({
  baseUrl: "https://staging.api.com",
  routes: "./routes.json",
  reporters: [
    slackReporter({
      webhookUrl: process.env.SCHEMIND_SLACK_WEBHOOK,
      notifyOn: ["warn", "breaking"],
    }),
    githubReporter({
      token: process.env.GITHUB_TOKEN,
      repo: process.env.GITHUB_REPOSITORY,
      pullNumber: Number(process.env.PR_NUMBER),
    }),
  ],
  ci: { failOn: "breaking" },
});

Generate types & mocks from what you've observed

Once schemind has learned your API's real shapes, export them as usable artifacts — no manual spec-writing:

schm codegen --target ts      --out src/api-types.ts   # TypeScript interfaces
schm codegen --target openapi --out openapi.json       # OpenAPI 3.0 spec
schm codegen --target json-schema                       # JSON Schema (stdout)
schm codegen --target msw     --out src/mocks.ts        # MSW request handlers

Already have a spec? Seed baselines from it instead of starting cold:

schm seed --from openapi.json

Local dashboard

schm dashboard
# → http://127.0.0.1:4500

Inspect endpoint health scores, trigger scans, and accept drift with one click.


Backend adapters

Install a satellite adapter on your backend to unlock the hash fast-path — schemind skips shape extraction entirely when the response struct hasn't changed.

| Backend | Package | Status | |---|---|---| | Go (net/http) | schemind-go | ✅ available | | Java / Spring Boot | schemind-java | ✅ available | | Python (FastAPI / Django) | schemind-py | ✅ available |


Why schemind?

  • No spec to maintain. Baselines are learned at runtime, not hand-written and left to rot.
  • Language-agnostic core. The same drift model (none / breaking / warn / info) works whether your backend is TypeScript, Go, Java, or Python.
  • Zero runtime dependencies. Ships lean, works anywhere JavaScript runs — browser, edge, Node.
  • Drop-in, not a rewrite. Wrap your existing fetch, add a middleware line, or wrap a query client — that's the whole integration.
  • CI-native. Fails builds on real breaking changes, not on cosmetic diffs, with configurable severity thresholds.

Contributing

Contributions are very welcome — see CONTRIBUTING.md to get started. Good first areas: new backend adapters, additional reporters, and codegen targets.

License

MIT · built by aminos