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

@wilsong/queryguard

v0.4.0

Published

Drop-in observability layer for Supabase apps. Catch silent failures, group issues, detect regressions, and surface impact.

Downloads

320

Readme

QueryGuard

Drop-in observability layer for Supabase apps.

Catch the silent failures Supabase dashboards miss. Instrument queries, group issues, detect regressions, and surface impact — with zero configuration.

npm version TypeScript License: MIT


Why QueryGuard

Supabase is great. PostgREST is fast. But neither tells you when:

  • An RLS policy silently returns 403 to a logged-in user
  • A query is taking 4 seconds on the /dashboard page
  • A race condition causes lesson_progress to return [] for 2% of users
  • An edge function started failing 3 hours after your last deploy
  • A fix you shipped last week re-opened an issue you already resolved

QueryGuard instruments your Supabase client at the fetch layer, groups related failures into tracked issues, scores them by impact, and alerts on regressions — all without requiring changes to your query code.


What It Catches

| Signal | How | |--------|-----| | RLS 403s | Intercepts PostgREST responses, detects policy failures | | Silent query failures | Captures 4xx/5xx before they reach your .then() | | RPC failures | Monitors /rest/v1/rpc/ endpoint errors separately | | Edge function errors | Tracks /functions/v1/ failures with function name | | Auth failures | Monitors /auth/v1/ errors (skips expected 401s) | | Slow queries | Flags requests exceeding configurable threshold (default 3s) | | Empty result anomalies | Detects [] responses on tables that should have data | | Client JS errors | window.onerror + unhandledrejection capture | | React render errors | QueryGuardErrorBoundary component |


Architecture

QueryGuard is split into two layers:

packages/queryguard          ← npm-installable SDK
├── src/
│   ├── types/               ← Canonical QGEvent model
│   ├── fingerprint/         ← Deterministic issue grouping
│   ├── redaction/           ← Secret/PII scrubbing pipeline
│   ├── normalize/           ← URL classification + event shaping
│   ├── transport/           ← Batching, retry, sendBeacon fallback
│   ├── client/              ← Browser guarded fetch + error capture
│   ├── server/              ← Server-side guarded fetch
│   └── react/               ← ErrorBoundary + ErrorLogger components

apps/dashboard (or your app)
├── src/app/api/error-log/   ← Ingestion endpoint
├── src/app/(admin)/errors/  ← Dashboard UI
└── src/lib/supabase/        ← Supabase client wrappers

SDK → Ingestion Endpoint → Dashboard

The SDK captures events client/server-side, batches them, and ships to your /api/error-log endpoint. The endpoint groups them into issues, detects regressions, fires webhooks, and updates error budgets. The dashboard visualizes everything.


Installation

Option A: npm package (standalone)

npm install queryguard
# or
pnpm add queryguard

Option B: Self-hosted dashboard (this repo)

The dashboard app in src/app/(admin)/admin/errors/ is the full-featured viewer. It runs inside your existing Next.js app — no separate deployment needed.


60-Second Setup

1. Initialize QueryGuard (client)

// src/lib/queryguard.ts
import { initQueryGuard } from "queryguard";

export const qg = initQueryGuard({
  endpoint: "/api/error-log",
  environment: process.env.NODE_ENV,
  deploy_version: process.env.NEXT_PUBLIC_DEPLOY_SHA,
});

2. Pass guardedFetch to your Supabase browser client

// src/lib/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr";
import { qg } from "@/lib/queryguard";

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    { global: { fetch: qg.guardedFetch } }
  );
}

3. Pass serverGuardedFetch to your Supabase server client

// src/lib/supabase/server.ts
import { createServerClient } from "@supabase/ssr";
import { createServerTransport, createServerGuardedFetch } from "queryguard/server";

const transport = createServerTransport({ endpoint: "/api/error-log" });
const serverGuardedFetch = createServerGuardedFetch(transport, {});

export async function createClient() {
  return createServerClient(url, key, {
    global: { fetch: serverGuardedFetch },
    // ...cookies
  });
}

4. Mount ErrorLogger in your root layout

// app/layout.tsx (client component or child of)
import { ErrorLogger } from "queryguard/react";
import { qg } from "@/lib/queryguard";

export default function Layout({ children }) {
  return (
    <>
      <ErrorLogger transport={qg.transport} />
      {children}
    </>
  );
}

That's it. QueryGuard is now capturing all Supabase traffic, grouping issues, and making them visible in your dashboard at /admin/errors.


SDK API Reference

Core

| Export | Description | |--------|-------------| | initQueryGuard(config) | Initialize client-side QueryGuard. Returns a handle. | | withQueryGuardSupabase(factory, config) | Convenience wrapper for Supabase client factories | | captureException(error, transport, config) | Manually capture an exception | | captureMessage(message, transport, config) | Manually capture a message |

Transport

| Export | Description | |--------|-------------| | BrowserTransport | Batching transport for browser environments | | createBrowserTransport(config) | Factory for browser transport | | createServerTransport(config) | Factory for server transport (no batching) |

Instrumentation

| Export | Description | |--------|-------------| | createGuardedFetch(transport, config) | Browser fetch wrapper | | createServerGuardedFetch(transport, config) | Server fetch wrapper | | setupGlobalErrorCapture(transport, config) | Install window error handlers | | initBreadcrumbTracker() | Start capturing user event trail |

React

| Export | Description | |--------|-------------| | ErrorLogger | Mount-once component: wires error capture + canary | | QueryGuardErrorBoundary | React error boundary with event capture |

Utilities

| Export | Description | |--------|-------------| | createFingerprint(...) | Generate deterministic issue fingerprint | | normalizeRoute(path) | Collapse dynamic segments to :id/:slug | | calculateImpactScore(...) | Score impact from page criticality + severity | | redactString(value) | Redact sensitive strings | | redactHeaders(headers) | Redact sensitive HTTP headers | | redactUrl(url) | Remove token query params from URLs | | redactObject(obj) | Deep-redact object fields |


Configuration

interface QGConfig {
  endpoint?: string;           // Default: "/api/error-log"
  project_id?: string;         // For multi-project support
  environment?: string;        // "production" | "development" | etc.
  deploy_version?: string;     // Git SHA or build ID
  api_key?: string;            // For hosted/SaaS mode
  slow_query_threshold_ms?: number;   // Default: 3000
  expected_data_tables?: string[];    // Tables where [] is suspicious
  page_criticality?: Record<string, number>; // Path → 1-10 score
  batch_size?: number;         // Default: 15
  flush_delay_ms?: number;     // Default: 2000
  capture_breadcrumbs?: boolean;     // Default: true
  capture_global_errors?: boolean;   // Default: true
  enable_canary?: boolean;     // Default: true
  quiet?: boolean;             // Suppress internal logs
}

Fingerprinting & Issue Grouping

QueryGuard generates deterministic fingerprints from:

  • Error category (silent_query_failure, rpc_failure, etc.)
  • Entity (table name, RPC name, edge function name)
  • HTTP status code
  • Normalized page path (UUIDs/slugs collapsed to :id/:slug)
  • First line of the Postgres error message

100 calls to the same broken RLS policy on the same route → 1 grouped issue, not 100 rows.


Impact Scoring

Every issue gets an impact score based on:

  • Page criticality (configurable, /dashboard/learn = 9, /admin = 3)
  • HTTP status severity (5xx = 3×, 403 = 2×, 400 = 1.5×)
  • Error category (silent_query_failure = 2×, slow_query = 1.5×)

Issues are sorted by impact in the dashboard — highest business impact first.


Redaction & Safety

QueryGuard never logs dangerous payloads. The redaction pipeline:

  • Strips Authorization, Cookie, apikey, and token headers
  • Redacts password, token, api_key, secret, and similar body fields
  • Scrubs JWT patterns, Bearer tokens, Stripe/Supabase keys via regex
  • Truncates body payloads at 1KB
  • Truncates metadata values at 500 chars
  • Handles circular references safely
  • Never logs its own transport failures (loop guard)

Dashboard Features

The admin dashboard at /admin/errors includes:

  • Issues — grouped, deduplicated, with regression detection
  • Raw Logs — expandable with breadcrumb trail, stack trace, metadata
  • Query Health — per-table failure/slow counts
  • Analytics — MTTR, SLA compliance, severity distribution, error-by-page
  • Error Budget — daily burn rate gauge
  • 7-Day Trend — hourly error chart
  • Config — webhook alerts (Slack/Discord), SLA settings, canary status
  • Bulk actions — resolve, ignore, tag multiple issues
  • CSV export — issues export for reporting

Trace Correlation (v0.1 foundations)

QueryGuard includes trace-ready fields in every event:

interface QGTraceContext {
  trace_id?: string;    // Request-scoped correlation ID
  span_id?: string;     // Span identifier
  parent_span_id?: string;
}

These allow linking: user action → fetch → API route → edge function → query event. Full OpenTelemetry compatibility is a future roadmap item.


Local Development

# Install dependencies
cd packages/queryguard
npm install

# Build
npm run build

# Type check
npm run typecheck

# Run tests
npm test

Roadmap

  • [ ] OpenTelemetry trace export
  • [ ] Hosted SaaS ingestion endpoint (multi-project)
  • [ ] Slack/Discord/PagerDuty alert integrations
  • [ ] Auto-resolve stale issues (configurable TTL)
  • [ ] Query performance regression detection across deploys
  • [ ] Supabase Storage monitoring
  • [ ] Realtime subscription error tracking
  • [ ] queryguard init CLI for zero-config setup

Contributing

  1. Fork and clone the repo
  2. cd packages/queryguard && npm install
  3. Make changes in src/
  4. Run npm test and npm run typecheck
  5. Submit a PR with a clear description

Please keep PRs focused. One change per PR.


License

MIT © QueryGuard Contributors


Built to catch what Supabase dashboards miss.